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        Validate.notNull(name);
023        value = name;
024        this.isProcessingInstruction = isProcessingInstruction;
025    }
026
027    public String nodeName() {
028        return "#declaration";
029    }
030
031    /**
032     * Get the name of this declaration.
033     * @return name of this declaration.
034     */
035    public String name() {
036        return coreValue();
037    }
038
039    /**
040     * Get the unencoded XML declaration.
041     * @return XML declaration
042     */
043    public String getWholeDeclaration() {
044        StringBuilder sb = StringUtil.borrowBuilder();
045        try {
046            getWholeDeclaration(sb, new Document.OutputSettings());
047        } catch (IOException e) {
048            throw new SerializationException(e);
049        }
050        return StringUtil.releaseBuilder(sb).trim();
051    }
052
053    private void getWholeDeclaration(Appendable accum, Document.OutputSettings out) throws IOException {
054        for (Attribute attribute : attributes()) {
055            String key = attribute.getKey();
056            String val = attribute.getValue();
057            if (!key.equals(nodeName())) { // skips coreValue (name)
058                accum.append(' ');
059                // basically like Attribute, but skip empty vals in XML
060                accum.append(key);
061                if (!val.isEmpty()) {
062                    accum.append("=\"");
063                    Entities.escape(accum, val, out, true, false, false, false);
064                    accum.append('"');
065                }
066            }
067        }
068    }
069
070    @Override
071    void outerHtmlHead(Appendable accum, int depth, Document.OutputSettings out) throws IOException {
072        accum
073            .append("<")
074            .append(isProcessingInstruction ? "!" : "?")
075            .append(coreValue());
076        getWholeDeclaration(accum, out);
077        accum
078            .append(isProcessingInstruction ? "!" : "?")
079            .append(">");
080    }
081
082    @Override
083    void outerHtmlTail(Appendable accum, int depth, Document.OutputSettings out) {
084    }
085
086    @Override
087    public String toString() {
088        return outerHtml();
089    }
090
091    @Override
092    public XmlDeclaration clone() {
093        return (XmlDeclaration) super.clone();
094    }
095}