diff --git a/pom.xml b/pom.xml
index 62050f6b..b4be05fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@ limitations under the License.
plexus-utils
- 3.1.2-SNAPSHOT
+ 3.2.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/Xpp3Dom.java b/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
index 3467ab4c..321b7855 100644
--- a/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
+++ b/src/main/java/org/codehaus/plexus/util/xml/Xpp3Dom.java
@@ -48,6 +48,11 @@ public class Xpp3Dom
protected Xpp3Dom parent;
+ /**
+ * @since 3.2.0
+ */
+ protected Object inputLocation;
+
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final Xpp3Dom[] EMPTY_DOM_ARRAY = new Xpp3Dom[0];
@@ -278,6 +283,26 @@ public void setParent( Xpp3Dom parent )
this.parent = parent;
}
+ // ----------------------------------------------------------------------
+ // Input location handling
+ // ----------------------------------------------------------------------
+
+ /**
+ * @since 3.2.0
+ */
+ public Object getInputLocation()
+ {
+ return inputLocation;
+ }
+
+ /**
+ * @since 3.2.0
+ */
+ public void setInputLocation( Object inputLocation )
+ {
+ this.inputLocation = inputLocation;
+ }
+
// ----------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java b/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java
index 3f8ce989..ffe108d5 100644
--- a/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java
+++ b/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java
@@ -37,7 +37,16 @@ public class Xpp3DomBuilder
public static Xpp3Dom build( Reader reader )
throws XmlPullParserException, IOException
{
- return build( reader, DEFAULT_TRIM );
+ return build( reader, null );
+ }
+
+ /**
+ * @since 3.2.0
+ */
+ public static Xpp3Dom build( Reader reader, InputLocationBuilder locationBuilder )
+ throws XmlPullParserException, IOException
+ {
+ return build( reader, DEFAULT_TRIM, locationBuilder );
}
public static Xpp3Dom build( InputStream is, String encoding )
@@ -68,13 +77,22 @@ public static Xpp3Dom build( InputStream is, String encoding, boolean trim )
public static Xpp3Dom build( Reader reader, boolean trim )
throws XmlPullParserException, IOException
+ {
+ return build( reader, trim, null );
+ }
+
+ /**
+ * @since 3.2.0
+ */
+ public static Xpp3Dom build( Reader reader, boolean trim, InputLocationBuilder locationBuilder )
+ throws XmlPullParserException, IOException
{
try
{
final XmlPullParser parser = new MXParser();
parser.setInput( reader );
- final Xpp3Dom xpp3Dom = build( parser, trim );
+ final Xpp3Dom xpp3Dom = build( parser, trim, locationBuilder );
reader.close();
reader = null;
@@ -94,6 +112,15 @@ public static Xpp3Dom build( XmlPullParser parser )
public static Xpp3Dom build( XmlPullParser parser, boolean trim )
throws XmlPullParserException, IOException
+ {
+ return build( parser, trim, null );
+ }
+
+ /**
+ * @since 3.2.0
+ */
+ public static Xpp3Dom build( XmlPullParser parser, boolean trim, InputLocationBuilder locationBuilder )
+ throws XmlPullParserException, IOException
{
List elements = new ArrayList();
@@ -113,6 +140,11 @@ public static Xpp3Dom build( XmlPullParser parser, boolean trim )
Xpp3Dom childConfiguration = new Xpp3Dom( rawName );
+ if ( locationBuilder != null )
+ {
+ childConfiguration.setInputLocation( locationBuilder.toInputLocation( parser ) );
+ }
+
int depth = elements.size();
if ( depth > 0 )
@@ -194,4 +226,14 @@ else if ( eventType == XmlPullParser.END_TAG )
throw new IllegalStateException( "End of document found before returning to 0 depth" );
}
+
+ /**
+ * Input location builder interface, to be implemented to choose how to store data.
+ *
+ * @since 3.2.0
+ */
+ public static interface InputLocationBuilder
+ {
+ Object toInputLocation( XmlPullParser parser );
+ }
}
diff --git a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java
index 302443c2..0c8e5a17 100644
--- a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java
+++ b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java
@@ -175,6 +175,35 @@ public void testEscapingInAttributes()
assertEquals( "Compare stringified DOMs", newString, s );
}
+ @Test
+ public void testInputLocationTracking()
+ throws IOException, XmlPullParserException
+ {
+ Xpp3DomBuilder.InputLocationBuilder ilb = new Xpp3DomBuilder.InputLocationBuilder() {
+ public Object toInputLocation( XmlPullParser parser )
+ {
+ return parser.getLineNumber(); // store only line number as a simple Integer
+ }
+
+ };
+ Xpp3Dom dom = Xpp3DomBuilder.build( new StringReader( createDomString() ), true, ilb );
+ Xpp3Dom expectedDom = createExpectedDom();
+ assertEquals( "root input location", expectedDom.getInputLocation(), dom.getInputLocation() );
+ for( int i = 0; i < dom.getChildCount(); i++ )
+ {
+ Xpp3Dom elt = dom.getChild( i );
+ Xpp3Dom expectedElt = expectedDom.getChild( i );
+ assertEquals( elt.getName() + " input location", expectedElt.getInputLocation(), elt.getInputLocation() );
+
+ if ( "el2".equals( elt.getName() ) )
+ {
+ Xpp3Dom el3 = elt.getChild( 0 );
+ Xpp3Dom expectedEl3 = expectedElt.getChild( 0 );
+ assertEquals( el3.getName() + " input location", expectedEl3.getInputLocation(), el3.getInputLocation() );
+ }
+ }
+ }
+
private static String getAttributeEncodedString()
{
StringBuilder domString = new StringBuilder();
@@ -237,23 +266,33 @@ private static String createDomString()
private static Xpp3Dom createExpectedDom()
{
+ int line = 1;
Xpp3Dom expectedDom = new Xpp3Dom( "root" );
+ expectedDom.setInputLocation( line );
Xpp3Dom el1 = new Xpp3Dom( "el1" );
+ el1.setInputLocation( ++line );
el1.setValue( "element1" );
expectedDom.addChild( el1 );
+ ++line; // newline trimmed in Xpp3Dom but not in source
Xpp3Dom el2 = new Xpp3Dom( "el2" );
+ el2.setInputLocation( ++line );
el2.setAttribute( "att2", "attribute2\nnextline" );
expectedDom.addChild( el2 );
Xpp3Dom el3 = new Xpp3Dom( "el3" );
+ el3.setInputLocation( ++line );
el3.setAttribute( "att3", "attribute3" );
el3.setValue( "element3" );
el2.addChild( el3 );
+ ++line;
Xpp3Dom el4 = new Xpp3Dom( "el4" );
+ el4.setInputLocation( ++line );
el4.setValue( "" );
expectedDom.addChild( el4 );
Xpp3Dom el5 = new Xpp3Dom( "el5" );
+ el5.setInputLocation( ++line );
expectedDom.addChild( el5 );
Xpp3Dom el6 = new Xpp3Dom( "el6" );
+ el6.setInputLocation( ++line );
el6.setAttribute( "xml:space", "preserve" );
el6.setValue( " do not trim " );
expectedDom.addChild( el6 );