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