1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.codehaus.plexus.util.xml;
20
21 import java.io.IOException;
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import org.apache.maven.api.xml.Dom;
28 import org.codehaus.plexus.util.StringUtils;
29 import org.codehaus.plexus.util.xml.pull.XmlSerializer;
30
31
32
33
34 public class Xpp3Dom implements Serializable {
35 private static final String[] EMPTY_STRING_ARRAY = new String[0];
36
37 private static final Xpp3Dom[] EMPTY_DOM_ARRAY = new Xpp3Dom[0];
38
39 public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
40
41 public static final String CHILDREN_COMBINATION_MERGE = "merge";
42
43 public static final String CHILDREN_COMBINATION_APPEND = "append";
44
45
46
47
48
49
50 public static final String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
51
52 public static final String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
53
54 public static final String SELF_COMBINATION_OVERRIDE = "override";
55
56 public static final String SELF_COMBINATION_MERGE = "merge";
57
58 public static final String SELF_COMBINATION_REMOVE = "remove";
59
60
61
62
63
64
65
66 public static final String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
67
68 private ChildrenTracking childrenTracking;
69 private Dom dom;
70
71 public Xpp3Dom(String name) {
72 this.dom = new org.apache.maven.internal.xml.Xpp3Dom(name);
73 }
74
75
76
77
78
79
80 public Xpp3Dom(String name, Object inputLocation) {
81 this.dom = new org.apache.maven.internal.xml.Xpp3Dom(name, null, null, null, inputLocation);
82 }
83
84
85
86
87
88 public Xpp3Dom(Xpp3Dom src) {
89 this(src, src.getName());
90 }
91
92
93
94
95
96
97 public Xpp3Dom(Xpp3Dom src, String name) {
98 this.dom = new org.apache.maven.internal.xml.Xpp3Dom(src.dom, name);
99 }
100
101 public Xpp3Dom(Dom dom) {
102 this.dom = dom;
103 }
104
105 public Xpp3Dom(Dom dom, Xpp3Dom parent) {
106 this.dom = dom;
107 this.childrenTracking = parent::replace;
108 }
109
110 public Xpp3Dom(Dom dom, ChildrenTracking childrenTracking) {
111 this.dom = dom;
112 this.childrenTracking = childrenTracking;
113 }
114
115 public Dom getDom() {
116 return dom;
117 }
118
119
120
121
122
123 public String getName() {
124 return dom.getName();
125 }
126
127
128
129
130
131 public String getValue() {
132 return dom.getValue();
133 }
134
135 public void setValue(String value) {
136 update(new org.apache.maven.internal.xml.Xpp3Dom(
137 dom.getName(), value, dom.getAttributes(), dom.getChildren(), dom.getInputLocation()));
138 }
139
140
141
142
143
144 public String[] getAttributeNames() {
145 return dom.getAttributes().keySet().toArray(EMPTY_STRING_ARRAY);
146 }
147
148 public String getAttribute(String name) {
149 return dom.getAttribute(name);
150 }
151
152
153
154
155
156
157
158 public boolean removeAttribute(String name) {
159 if (!StringUtils.isEmpty(name)) {
160 Map<String, String> attrs = new HashMap<>(dom.getAttributes());
161 boolean ret = attrs.remove(name) != null;
162 if (ret) {
163 update(new org.apache.maven.internal.xml.Xpp3Dom(
164 dom.getName(), dom.getValue(), attrs, dom.getChildren(), dom.getInputLocation()));
165 }
166 return ret;
167 }
168 return false;
169 }
170
171
172
173
174
175
176
177 public void setAttribute(String name, String value) {
178 if (null == value) {
179 throw new NullPointerException("Attribute value can not be null");
180 }
181 if (null == name) {
182 throw new NullPointerException("Attribute name can not be null");
183 }
184 Map<String, String> attrs = new HashMap<>(dom.getAttributes());
185 attrs.put(name, value);
186 update(new org.apache.maven.internal.xml.Xpp3Dom(
187 dom.getName(), dom.getValue(), attrs, dom.getChildren(), dom.getInputLocation()));
188 }
189
190
191
192
193
194 public Xpp3Dom getChild(int i) {
195 return new Xpp3Dom(dom.getChildren().get(i), this);
196 }
197
198 public Xpp3Dom getChild(String name) {
199 Dom child = dom.getChild(name);
200 return child != null ? new Xpp3Dom(child, this) : null;
201 }
202
203 public void addChild(Xpp3Dom xpp3Dom) {
204 List<Dom> children = new ArrayList<>(dom.getChildren());
205 children.add(xpp3Dom.dom);
206 xpp3Dom.childrenTracking = this::replace;
207 update(new org.apache.maven.internal.xml.Xpp3Dom(
208 dom.getName(), dom.getValue(), dom.getAttributes(), children, dom.getInputLocation()));
209 }
210
211 public Xpp3Dom[] getChildren() {
212 return dom.getChildren().stream().map(d -> new Xpp3Dom(d, this)).toArray(Xpp3Dom[]::new);
213 }
214
215 public Xpp3Dom[] getChildren(String name) {
216 return dom.getChildren().stream()
217 .filter(c -> c.getName().equals(name))
218 .map(d -> new Xpp3Dom(d, this))
219 .toArray(Xpp3Dom[]::new);
220 }
221
222 public int getChildCount() {
223 return dom.getChildren().size();
224 }
225
226 public void removeChild(int i) {
227 List<Dom> children = new ArrayList<>(dom.getChildren());
228 children.remove(i);
229 update(new org.apache.maven.internal.xml.Xpp3Dom(
230 dom.getName(), dom.getValue(), dom.getAttributes(), children, dom.getInputLocation()));
231 }
232
233 public void removeChild(Xpp3Dom child) {
234 List<Dom> children = new ArrayList<>(dom.getChildren());
235 children.remove(child.dom);
236 update(new org.apache.maven.internal.xml.Xpp3Dom(
237 dom.getName(), dom.getValue(), dom.getAttributes(), children, dom.getInputLocation()));
238 }
239
240
241
242
243
244 public Xpp3Dom getParent() {
245 throw new UnsupportedOperationException();
246 }
247
248 public void setParent(Xpp3Dom parent) {}
249
250
251
252
253
254
255
256
257
258 public Object getInputLocation() {
259 return dom.getInputLocation();
260 }
261
262
263
264
265
266 public void setInputLocation(Object inputLocation) {
267 update(new org.apache.maven.internal.xml.Xpp3Dom(
268 dom.getName(), dom.getValue(), dom.getAttributes(), dom.getChildren(), inputLocation));
269 }
270
271
272
273
274
275 public void writeToSerializer(String namespace, XmlSerializer serializer) throws IOException {
276
277
278 SerializerXMLWriter xmlWriter = new SerializerXMLWriter(namespace, serializer);
279 Xpp3DomWriter.write(xmlWriter, this);
280 if (xmlWriter.getExceptions().size() > 0) {
281 throw (IOException) xmlWriter.getExceptions().get(0);
282 }
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 private static void mergeIntoXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride) {
323
324 if (recessive == null) {
325 return;
326 }
327 dominant.dom = dominant.dom.merge(recessive.dom, childMergeOverride);
328 }
329
330
331
332
333
334
335
336
337
338
339
340
341 public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride) {
342 if (dominant != null) {
343 mergeIntoXpp3Dom(dominant, recessive, childMergeOverride);
344 return dominant;
345 }
346 return recessive;
347 }
348
349
350
351
352
353
354
355
356
357
358
359 public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive) {
360 if (dominant != null) {
361 mergeIntoXpp3Dom(dominant, recessive, null);
362 return dominant;
363 }
364 return recessive;
365 }
366
367
368
369
370
371 @Override
372 public boolean equals(Object obj) {
373 if (obj == this) {
374 return true;
375 }
376
377 if (!(obj instanceof Xpp3Dom)) {
378 return false;
379 }
380
381 Xpp3Dom dom = (Xpp3Dom) obj;
382 return this.dom.equals(dom.dom);
383 }
384
385 @Override
386 public int hashCode() {
387 return dom.hashCode();
388 }
389
390 @Override
391 public String toString() {
392 return dom.toString();
393 }
394
395 public String toUnescapedString() {
396 return ((Xpp3Dom) dom).toUnescapedString();
397 }
398
399 public static boolean isNotEmpty(String str) {
400 return ((str != null) && (str.length() > 0));
401 }
402
403 public static boolean isEmpty(String str) {
404 return ((str == null) || (str.trim().length() == 0));
405 }
406
407 private void update(Dom dom) {
408 if (childrenTracking != null) {
409 childrenTracking.replace(this.dom, dom);
410 }
411 this.dom = dom;
412 }
413
414 private boolean replace(Object prevChild, Object newChild) {
415 List<Dom> children = new ArrayList<>(dom.getChildren());
416 children.replaceAll(d -> d == prevChild ? (Dom) newChild : d);
417 update(new org.apache.maven.internal.xml.Xpp3Dom(
418 dom.getName(), dom.getValue(), dom.getAttributes(), children, dom.getInputLocation()));
419 return true;
420 }
421
422 public void setChildrenTracking(ChildrenTracking childrenTracking) {
423 this.childrenTracking = childrenTracking;
424 }
425
426 @FunctionalInterface
427 public interface ChildrenTracking {
428 boolean replace(Object oldDelegate, Object newDelegate);
429 }
430 }