Element.java

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