Element.java

  1package eu.siacs.conversations.xml;
  2
  3import androidx.annotation.NonNull;
  4
  5import com.google.common.base.Optional;
  6import com.google.common.collect.ImmutableList;
  7import com.google.common.primitives.Ints;
  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 String toString() {
182		final StringBuilder elementOutput = new StringBuilder();
183		if (childNodes.size() == 0) {
184			Tag emptyTag = Tag.empty(name);
185			emptyTag.setAttributes(this.attributes);
186			elementOutput.append(emptyTag.toString());
187		} else {
188			Tag startTag = Tag.start(name);
189			startTag.setAttributes(this.attributes);
190			elementOutput.append(startTag);
191			for (Node child : ImmutableList.copyOf(childNodes)) {
192				elementOutput.append(child.toString());
193			}
194			Tag endTag = Tag.end(name);
195			elementOutput.append(endTag);
196		}
197		return elementOutput.toString();
198	}
199
200	public Element removeAttribute(String name) {
201		this.attributes.remove(name);
202		return this;
203	}
204
205	public Element setAttributes(Hashtable<String, String> attributes) {
206		this.attributes = attributes;
207		return this;
208	}
209
210	public String getAttribute(String name) {
211		if (this.attributes.containsKey(name)) {
212			return this.attributes.get(name);
213		} else {
214			return null;
215		}
216	}
217
218	public Optional<Integer> getOptionalIntAttribute(final String name) {
219		final String value = getAttribute(name);
220		if (value == null) {
221			return Optional.absent();
222		}
223		return Optional.fromNullable(Ints.tryParse(value));
224	}
225
226	public Jid getAttributeAsJid(String name) {
227		final String jid = this.getAttribute(name);
228		if (jid != null && !jid.isEmpty()) {
229			try {
230				return Jid.ofEscaped(jid);
231			} catch (final IllegalArgumentException e) {
232				return InvalidJid.of(jid, this instanceof MessagePacket);
233			}
234		}
235		return null;
236	}
237
238	public Hashtable<String, String> getAttributes() {
239		return this.attributes;
240	}
241
242	public final String getName() {
243		return name;
244	}
245
246	public void clearChildren() {
247		this.children.clear();
248		this.childNodes.clear();
249	}
250
251	public void setAttribute(String name, long value) {
252		this.setAttribute(name, Long.toString(value));
253	}
254
255	public void setAttribute(String name, int value) {
256		this.setAttribute(name, Integer.toString(value));
257	}
258
259	public boolean getAttributeAsBoolean(String name) {
260		String attr = getAttribute(name);
261		return (attr != null && (attr.equalsIgnoreCase("true") || attr.equalsIgnoreCase("1")));
262	}
263
264	public String getNamespace() {
265		return getAttribute("xmlns");
266	}
267}