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