Element.java

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