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