From 177a0cd86dda0cc07045628b2a5ad47a2559edb9 Mon Sep 17 00:00:00 2001 From: rfscholte Date: Sat, 7 Dec 2019 13:26:17 +0100 Subject: [PATCH] Support combine.keys --- pom.xml | 2 +- .../plexus/util/xml/Xpp3DomUtils.java | 39 ++++++++++++++++++- .../plexus/util/xml/Xpp3DomUtilsTest.java | 35 +++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index f6602acd..93014125 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ limitations under the License. plexus-utils - 3.3.1-SNAPSHOT + 3.4.0-SNAPSHOT Plexus Common Utilities A collection of various utility classes to ease working with strings, files, command lines, XML and diff --git a/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomUtils.java b/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomUtils.java index 70d00143..71efe467 100644 --- a/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomUtils.java +++ b/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomUtils.java @@ -19,9 +19,7 @@ import org.codehaus.plexus.util.xml.pull.XmlSerializer; import java.io.IOException; -import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; /** @author Jason van Zyl */ @@ -52,6 +50,14 @@ public class Xpp3DomUtils * @since 3.0.22 */ public static final String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id"; + + /** + * In case of complex XML structures, combining can be done based on keys. + * This is a comma separated list of attribute names. + * + * @Since 3.4.0 + */ + public static final String KEYS_COMBINATION_MODE_ATTRIBUTE = "combine.keys"; /** * This default mode for combining a DOM node during merge means that where element names match, the process will @@ -106,6 +112,8 @@ public void writeToSerializer( String namespace, XmlSerializer serializer, Xpp3D *
    *
  1. if 'combine.id' is set and there is a corresponding dominant child (matched by value of 'combine.id'), * merge the two.
  2. + *
  3. if 'combine.keys' is set and there is a corresponding dominant child (matched by value of key elements), + * merge the two.
  4. *
  5. if mergeChildren == true and there is a corresponding dominant child (matched by element name), * merge the two.
  6. *
  7. otherwise, add the recessive child as a new child on the dominant root node.
  8. @@ -167,6 +175,7 @@ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boole for ( Xpp3Dom recessiveChild : children ) { String idValue = recessiveChild.getAttribute( ID_COMBINATION_MODE_ATTRIBUTE ); + String keysValue = recessiveChild.getAttribute( KEYS_COMBINATION_MODE_ATTRIBUTE ); Xpp3Dom childDom = null; if ( isNotEmpty( idValue ) ) @@ -181,6 +190,32 @@ private static void mergeIntoXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boole } } } + else if ( isNotEmpty( keysValue ) ) + { + String[] keys = keysValue.split( "," ); + Map recessiveKeyValues = new HashMap( keys.length ); + for ( String key : keys ) + { + recessiveKeyValues.put( key, recessiveChild.getChild( key ).getValue() ); + } + + for ( Xpp3Dom dominantChild : dominant.getChildren() ) + { + Map dominantKeyValues = new HashMap( keys.length ); + for ( String key : keys ) + { + dominantKeyValues.put( key, dominantChild.getChild( key ).getValue() ); + } + + if ( recessiveKeyValues.equals( dominantKeyValues ) ) + { + childDom = dominantChild; + // we have a match, so don't append but merge + mergeChildren = true; + } + } + + } else { childDom = dominant.getChild( recessiveChild.getName() ); diff --git a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomUtilsTest.java b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomUtilsTest.java index f4d0eb04..e5a68e77 100644 --- a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomUtilsTest.java +++ b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomUtilsTest.java @@ -60,6 +60,41 @@ public void testCombineId() assertEquals( "right", p2.getChild( "value" ).getInputLocation() ); } + @Test + public void testCombineKeys() + throws Exception + { + String lhs = "" + "LHS-ONLYLHS" + + "TOOVERWRITELHS" + ""; + + String rhs = "" + "RHS-ONLYRHS" + + "TOOVERWRITERHS" + ""; + + Xpp3Dom leftDom = Xpp3DomBuilder.build( new StringReader( lhs ), new FixedInputLocationBuilder( "left" ) ); + Xpp3Dom rightDom = Xpp3DomBuilder.build( new StringReader( rhs ), new FixedInputLocationBuilder( "right" ) ); + + Xpp3Dom mergeResult = Xpp3DomUtils.mergeXpp3Dom( leftDom, rightDom, true ); + assertEquals( 3, mergeResult.getChildren( "property" ).length ); + + Xpp3Dom p0 = mergeResult.getChildren( "property" )[0]; + assertEquals( "LHS-ONLY", p0.getChild( "name" ).getValue() ); + assertEquals( "left", p0.getChild( "name" ).getInputLocation() ); + assertEquals( "LHS", p0.getChild( "value" ).getValue() ); + assertEquals( "left", p0.getChild( "value" ).getInputLocation() ); + + Xpp3Dom p1 = mergeResult.getChildren( "property" )[1]; + assertEquals( "TOOVERWRITE", mergeResult.getChildren( "property" )[1].getChild( "name" ).getValue() ); + assertEquals( "left", p1.getChild( "name" ).getInputLocation() ); + assertEquals( "LHS", mergeResult.getChildren( "property" )[1].getChild( "value" ).getValue() ); + assertEquals( "left", p1.getChild( "value" ).getInputLocation() ); + + Xpp3Dom p2 = mergeResult.getChildren( "property" )[2]; + assertEquals( "RHS-ONLY", mergeResult.getChildren( "property" )[2].getChild( "name" ).getValue() ); + assertEquals( "right", p2.getChild( "name" ).getInputLocation() ); + assertEquals( "RHS", mergeResult.getChildren( "property" )[2].getChild( "value" ).getValue() ); + assertEquals( "right", p2.getChild( "value" ).getInputLocation() ); + } + private static class FixedInputLocationBuilder implements Xpp3DomBuilder.InputLocationBuilder {