Element.java

  1package eu.siacs.conversations.xml;
  2
  3import com.google.common.base.Optional;
  4import com.google.common.primitives.Ints;
  5
  6import org.jetbrains.annotations.NotNull;
  7
  8import java.util.ArrayList;
  9import java.util.Collection;
 10import java.util.Hashtable;
 11import java.util.List;
 12import java.util.stream.Collectors;
 13
 14import eu.siacs.conversations.utils.XmlHelper;
 15import eu.siacs.conversations.xmpp.InvalidJid;
 16import eu.siacs.conversations.xmpp.Jid;
 17import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 18
 19public class Element implements Node {
 20	private final String name;
 21	private Hashtable<String, String> attributes = new Hashtable<>();
 22	private List<Element> children = new ArrayList<>();
 23	private List<Node> childNodes = new ArrayList<>();
 24
 25	public Element(String name) {
 26		this.name = name;
 27	}
 28
 29	public Element(String name, String xmlns) {
 30		this.name = name;
 31		this.setAttribute("xmlns", xmlns);
 32	}
 33
 34	public Node prependChild(Node child) {
 35		childNodes.add(0, child);
 36		if (child instanceof Element) children.add(0, (Element) child);
 37		return child;
 38	}
 39
 40	public Node addChild(Node child) {
 41		childNodes.add(child);
 42		if (child instanceof Element) children.add((Element) child);
 43		return child;
 44	}
 45
 46	public Element addChild(String name) {
 47		Element child = new Element(name);
 48		childNodes.add(child);
 49		children.add(child);
 50		return child;
 51	}
 52
 53	public Element addChild(String name, String xmlns) {
 54		Element child = new Element(name);
 55		child.setAttribute("xmlns", xmlns);
 56		childNodes.add(child);
 57		children.add(child);
 58		return child;
 59	}
 60
 61	public void addChildren(final Collection<? extends Node> children) {
 62		if (children == null) return;
 63
 64		this.childNodes.addAll(children);
 65		for (Node node : children) {
 66			if (node instanceof Element) {
 67				this.children.add((Element) node);
 68			}
 69		}
 70	}
 71
 72	public void removeChild(Node child) {
 73		this.childNodes.remove(child);
 74		if (child instanceof Element) this.children.remove(child);
 75	}
 76
 77	public Element setContent(String content) {
 78		clearChildren();
 79		if (content != null) this.childNodes.add(new TextNode(content));
 80		return this;
 81	}
 82
 83	public Element findChild(String name) {
 84		for (Element child : this.children) {
 85			if (child.getName().equals(name)) {
 86				return child;
 87			}
 88		}
 89		return null;
 90	}
 91
 92	public String findChildContent(String name) {
 93		Element element = findChild(name);
 94		return element == null ? null : element.getContent();
 95	}
 96
 97	public LocalizedContent findInternationalizedChildContentInDefaultNamespace(String name) {
 98		return LocalizedContent.get(this, name);
 99	}
100
101	public Element findChild(String name, String xmlns) {
102		for (Element child : this.children) {
103			if (name.equals(child.getName()) && xmlns.equals(child.getAttribute("xmlns"))) {
104				return child;
105			}
106		}
107		return null;
108	}
109
110	public Element findChildEnsureSingle(String name, String xmlns) {
111		final List<Element> results = new ArrayList<>();
112		for (Element child : this.children) {
113			if (name.equals(child.getName()) && xmlns.equals(child.getAttribute("xmlns"))) {
114				results.add(child);
115			}
116		}
117		if (results.size() == 1) {
118			return results.get(0);
119		}
120		return null;
121	}
122
123	public String findChildContent(String name, String xmlns) {
124		Element element = findChild(name,xmlns);
125		return element == null ? null : element.getContent();
126	}
127
128	public boolean hasChild(final String name) {
129		return findChild(name) != null;
130	}
131
132	public boolean hasChild(final String name, final String xmlns) {
133		return findChild(name, xmlns) != null;
134	}
135
136	public final List<Element> getChildren() {
137		return this.children;
138	}
139
140	// Deprecated: you probably want bindTo or replaceChildren
141	public Element setChildren(List<Element> children) {
142		this.childNodes = new ArrayList(children);
143		this.children = children;
144		return this;
145	}
146
147	public void replaceChildren(List<Element> children) {
148		this.childNodes.clear();
149		this.childNodes.addAll(children);
150		this.children.clear();
151		this.children.addAll(children);
152	}
153
154	public void bindTo(Element original) {
155		this.attributes = original.attributes;
156		this.childNodes = original.childNodes;
157		this.children = original.children;
158	}
159
160	public final String getContent() {
161		return this.childNodes.stream().map(Node::getContent).filter(c -> c != null).collect(Collectors.joining());
162	}
163
164	public Element setAttribute(String name, String value) {
165		if (name != null && value != null) {
166			this.attributes.put(name, value);
167		}
168		return this;
169	}
170
171	public Element setAttribute(String name, Jid value) {
172		if (name != null && value != null) {
173			this.attributes.put(name, value.toEscapedString());
174		}
175		return this;
176	}
177
178	public Element removeAttribute(String name) {
179		this.attributes.remove(name);
180		return this;
181	}
182
183	public Element setAttributes(Hashtable<String, String> attributes) {
184		this.attributes = attributes;
185		return this;
186	}
187
188	public String getAttribute(String name) {
189		if (this.attributes.containsKey(name)) {
190			return this.attributes.get(name);
191		} else {
192			return null;
193		}
194	}
195
196	public Optional<Integer> getOptionalIntAttribute(final String name) {
197		final String value = getAttribute(name);
198		if (value == null) {
199			return Optional.absent();
200		}
201		return Optional.fromNullable(Ints.tryParse(value));
202	}
203
204	public Jid getAttributeAsJid(String name) {
205		final String jid = this.getAttribute(name);
206		if (jid != null && !jid.isEmpty()) {
207			try {
208				return Jid.ofEscaped(jid);
209			} catch (final IllegalArgumentException e) {
210				return InvalidJid.of(jid, this instanceof MessagePacket);
211			}
212		}
213		return null;
214	}
215
216	public Hashtable<String, String> getAttributes() {
217		return this.attributes;
218	}
219
220	@NotNull
221	public String toString() {
222		final StringBuilder elementOutput = new StringBuilder();
223		if (childNodes.size() == 0) {
224			Tag emptyTag = Tag.empty(name);
225			emptyTag.setAttributes(this.attributes);
226			elementOutput.append(emptyTag.toString());
227		} else {
228			Tag startTag = Tag.start(name);
229			startTag.setAttributes(this.attributes);
230			elementOutput.append(startTag);
231			for (Node child : childNodes) {
232				elementOutput.append(child.toString());
233			}
234			Tag endTag = Tag.end(name);
235			elementOutput.append(endTag);
236		}
237		return elementOutput.toString();
238	}
239
240	public final String getName() {
241		return name;
242	}
243
244	public void clearChildren() {
245		this.children.clear();
246		this.childNodes.clear();
247	}
248
249	public void setAttribute(String name, long value) {
250		this.setAttribute(name, Long.toString(value));
251	}
252
253	public void setAttribute(String name, int value) {
254		this.setAttribute(name, Integer.toString(value));
255	}
256
257	public boolean getAttributeAsBoolean(String name) {
258		String attr = getAttribute(name);
259		return (attr != null && (attr.equalsIgnoreCase("true") || attr.equalsIgnoreCase("1")));
260	}
261
262	public String getNamespace() {
263		return getAttribute("xmlns");
264	}
265}