001package org.jsoup.nodes; 002 003import org.jsoup.internal.QuietAppendable; 004import org.jsoup.internal.StringUtil; 005 006 007/** 008 * An XML declaration, such as {@code <?xml version="1.0"?>}, or a markup declaration, such as {@code <!ELEMENT ...>}. 009 * Use {@link ProcessingInstruction} for other {@code <?target data?>} nodes. 010 * Declaration values are available through {@link #attributes()} and {@link #attr(String)}. 011 */ 012public class XmlDeclaration extends LeafNode { 013 014 /** Whether this is a markup declaration. */ 015 private final boolean isMarkupDeclaration; 016 017 /** 018 * Creates an XML declaration or markup declaration. 019 * @param name the declaration name, such as {@code xml} or {@code ELEMENT} 020 * @param isMarkupDeclaration {@code true} to create {@code <!name ...>}; {@code false} to create {@code <?name ...?>} 021 */ 022 public XmlDeclaration(String name, boolean isMarkupDeclaration) { 023 super(name); 024 this.isMarkupDeclaration = isMarkupDeclaration; 025 } 026 027 @Override public String nodeName() { 028 return "#declaration"; 029 } 030 031 /** 032 * Gets the declaration name. 033 * @return the declaration name 034 */ 035 public String name() { 036 return coreValue(); 037 } 038 039 /** 040 * Gets the declaration data, without its name or delimiters. 041 * @return the declaration data 042 */ 043 public String getWholeDeclaration() { 044 StringBuilder sb = StringUtil.borrowBuilder(); 045 getWholeDeclaration(QuietAppendable.wrap(sb), new Document.OutputSettings()); 046 return StringUtil.releaseBuilder(sb).trim(); 047 } 048 049 private void getWholeDeclaration(QuietAppendable accum, Document.OutputSettings out) { 050 for (Attribute attribute : attributes()) { 051 String key = attribute.getKey(); 052 String val = attribute.getValue(); 053 if (!key.equals(nodeName())) { // skips coreValue (name) 054 accum.append(' '); 055 // basically like Attribute, but skip empty vals in XML 056 accum.append(key); 057 if (!val.isEmpty()) { 058 accum.append("=\""); 059 Entities.escape(accum, val, out, Entities.ForAttribute); 060 accum.append('"'); 061 } 062 } 063 } 064 } 065 066 @Override 067 void outerHtmlHead(QuietAppendable accum, Document.OutputSettings out) { 068 accum 069 .append("<") 070 .append(isMarkupDeclaration ? "!" : "?") 071 .append(coreValue()); 072 getWholeDeclaration(accum, out); 073 accum 074 .append(isMarkupDeclaration ? "" : "?") 075 .append(">"); 076 } 077 078 @Override 079 void outerHtmlTail(QuietAppendable accum, Document.OutputSettings out) { 080 } 081 082 @Override 083 public String toString() { 084 return outerHtml(); 085 } 086 087 @Override 088 public XmlDeclaration clone() { 089 return (XmlDeclaration) super.clone(); 090 } 091}