diff --git a/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java b/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
index 49b25f89..a7026384 100644
--- a/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
+++ b/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
@@ -22,7 +22,6 @@
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -76,6 +75,8 @@ public class Xpp3Dom
public static final String SELF_COMBINATION_MERGE = "merge";
+ public static final String SELF_COMBINATION_REMOVE = "remove";
+
/**
* This default mode for combining a DOM node during merge means that where element names match, the process will
* try to merge the element attributes and values, rather than overriding the recessive element completely with the
@@ -301,6 +302,13 @@ public void removeChild( int i )
child.setParent( null );
}
+ public void removeChild( Xpp3Dom child )
+ {
+ childList.remove( child );
+ // In case of any dangling references
+ child.setParent( null );
+ }
+
// ----------------------------------------------------------------------
// Parent handling
// ----------------------------------------------------------------------
@@ -418,7 +426,7 @@ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boole
{
for ( String attr : recessive.attributes.keySet() )
{
- if ( isEmpty( dominant.getAttribute( attr ) ) )
+ if ( isEmpty( dominant.getAttribute( attr ) ) && !SELF_COMBINATION_MODE_ATTRIBUTE.equals( attr ) )
{
dominant.setAttribute( attr, recessive.getAttribute( attr ) );
}
@@ -489,7 +497,17 @@ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boole
else if ( it.hasNext() )
{
Xpp3Dom dominantChild = it.next();
- mergeIntoXpp3Dom( dominantChild, recessiveChild, childMergeOverride );
+
+ String dominantChildCombinationMode =
+ dominantChild.getAttribute( SELF_COMBINATION_MODE_ATTRIBUTE );
+ if ( SELF_COMBINATION_REMOVE.equals( dominantChildCombinationMode ) )
+ {
+ dominant.removeChild( dominantChild );
+ }
+ else
+ {
+ mergeIntoXpp3Dom( dominantChild, recessiveChild, childMergeOverride );
+ }
}
}
}
diff --git a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java
index 04444f31..35fb5590 100644
--- a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java
+++ b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java
@@ -329,6 +329,36 @@ public void testDupeChildren()
assertEquals( "y", dom.getChild( "foo" ).getValue() );
}
+ @Test
+ public void testShouldRemoveEntireElementWithAttributesAndChildren()
+ throws Exception
+ {
+ String dominantStr = "";
+ String recessiveStr = "parameter";
+ Xpp3Dom dominantConfig = Xpp3DomBuilder.build( new StringReader( dominantStr ) );
+ Xpp3Dom recessiveConfig = Xpp3DomBuilder.build( new StringReader( recessiveStr ) );
+
+ Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( dominantConfig, recessiveConfig );
+
+ assertEquals( 0, result.getChildCount() );
+ assertEquals( "config", result.getName() );
+ }
+
+ @Test
+ public void testShouldRemoveDoNotRemoveTagWhenSwappedInputDOMs()
+ throws Exception
+ {
+ String dominantStr = "";
+ String recessiveStr = "parameter";
+ Xpp3Dom dominantConfig = Xpp3DomBuilder.build( new StringReader( dominantStr ) );
+ Xpp3Dom recessiveConfig = Xpp3DomBuilder.build( new StringReader( recessiveStr ) );
+
+ // same DOMs as testShouldRemoveEntireElementWithAttributesAndChildren(), swapping dominant <--> recessive
+ Xpp3Dom result = Xpp3Dom.mergeXpp3Dom( recessiveConfig, dominantConfig );
+
+ assertEquals( recessiveConfig.toString(), result.toString() );
+ }
+
private static class FixedInputLocationBuilder
implements Xpp3DomBuilder.InputLocationBuilder
{