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