001package org.jsoup.nodes;
002
003import java.util.List;
004
005/**
006 A node that does not hold any children. E.g.: {@link TextNode}, {@link DataNode}, {@link Comment}.
007 */
008public abstract class LeafNode extends Node {
009    Object value; // either a string value, or an attribute map (in the rare case multiple attributes are set)
010
011    protected final boolean hasAttributes() {
012        return value instanceof Attributes;
013    }
014
015    @Override
016    public final Attributes attributes() {
017        ensureAttributes();
018        return (Attributes) value;
019    }
020
021    private void ensureAttributes() {
022        if (!hasAttributes()) {
023            Object coreValue = value;
024            Attributes attributes = new Attributes();
025            value = attributes;
026            if (coreValue != null)
027                attributes.put(nodeName(), (String) coreValue);
028        }
029    }
030
031    String coreValue() {
032        return attr(nodeName());
033    }
034
035    void coreValue(String value) {
036        attr(nodeName(), value);
037    }
038
039    @Override
040    public String attr(String key) {
041        if (!hasAttributes()) {
042            return nodeName().equals(key) ? (String) value : EmptyString;
043        }
044        return super.attr(key);
045    }
046
047    @Override
048    public Node attr(String key, String value) {
049        if (!hasAttributes() && key.equals(nodeName())) {
050            this.value = value;
051        } else {
052            ensureAttributes();
053            super.attr(key, value);
054        }
055        return this;
056    }
057
058    @Override
059    public boolean hasAttr(String key) {
060        ensureAttributes();
061        return super.hasAttr(key);
062    }
063
064    @Override
065    public Node removeAttr(String key) {
066        ensureAttributes();
067        return super.removeAttr(key);
068    }
069
070    @Override
071    public String absUrl(String key) {
072        ensureAttributes();
073        return super.absUrl(key);
074    }
075
076    @Override
077    public String baseUri() {
078        return hasParent() ? parent().baseUri() : "";
079    }
080
081    @Override
082    protected void doSetBaseUri(String baseUri) {
083        // noop
084    }
085
086    @Override
087    public int childNodeSize() {
088        return 0;
089    }
090
091    @Override
092    public Node empty() {
093        return this;
094    }
095
096    @Override
097    protected List<Node> ensureChildNodes() {
098        return EmptyNodes;
099    }
100
101    @Override
102    protected LeafNode doClone(Node parent) {
103        LeafNode clone = (LeafNode) super.doClone(parent);
104
105        // Object value could be plain string or attributes - need to clone
106        if (hasAttributes())
107            clone.value = ((Attributes) value).clone();
108
109        return clone;
110    }
111}