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