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