001package org.jsoup.nodes; 002 003import org.jsoup.internal.QuietAppendable; 004import org.jsoup.internal.StringUtil; 005 006 007/** 008 * An XML Declaration. Includes support for treating the declaration contents as pseudo attributes. 009 */ 010public class XmlDeclaration extends LeafNode { 011 012 /** 013 First char is `!` if isDeclaration, like in {@code <!ENTITY ...>}. 014 Otherwise, is `?`, a processing instruction, like {@code <?xml .... ?>} (and note trailing `?`). 015 */ 016 private final boolean isDeclaration; 017 018 /** 019 * Create a new XML declaration 020 * @param name of declaration 021 * @param isDeclaration {@code true} if a declaration (first char is `!`), otherwise a processing instruction (first char is `?`). 022 */ 023 public XmlDeclaration(String name, boolean isDeclaration) { 024 super(name); 025 this.isDeclaration = isDeclaration; 026 } 027 028 @Override public String nodeName() { 029 return "#declaration"; 030 } 031 032 /** 033 * Get the name of this declaration. 034 * @return name of this declaration. 035 */ 036 public String name() { 037 return coreValue(); 038 } 039 040 /** 041 * Get the unencoded XML declaration. 042 * @return XML declaration 043 */ 044 public String getWholeDeclaration() { 045 StringBuilder sb = StringUtil.borrowBuilder(); 046 getWholeDeclaration(QuietAppendable.wrap(sb), new Document.OutputSettings()); 047 return StringUtil.releaseBuilder(sb).trim(); 048 } 049 050 private void getWholeDeclaration(QuietAppendable accum, Document.OutputSettings out) { 051 for (Attribute attribute : attributes()) { 052 String key = attribute.getKey(); 053 String val = attribute.getValue(); 054 if (!key.equals(nodeName())) { // skips coreValue (name) 055 accum.append(' '); 056 // basically like Attribute, but skip empty vals in XML 057 accum.append(key); 058 if (!val.isEmpty()) { 059 accum.append("=\""); 060 Entities.escape(accum, val, out, Entities.ForAttribute); 061 accum.append('"'); 062 } 063 } 064 } 065 } 066 067 @Override 068 void outerHtmlHead(QuietAppendable accum, Document.OutputSettings out) { 069 accum 070 .append("<") 071 .append(isDeclaration ? "!" : "?") 072 .append(coreValue()); 073 getWholeDeclaration(accum, out); 074 accum 075 .append(isDeclaration ? "" : "?") 076 .append(">"); 077 } 078 079 @Override 080 void outerHtmlTail(QuietAppendable accum, Document.OutputSettings out) { 081 } 082 083 @Override 084 public String toString() { 085 return outerHtml(); 086 } 087 088 @Override 089 public XmlDeclaration clone() { 090 return (XmlDeclaration) super.clone(); 091 } 092}