You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2021/09/17 14:23:54 UTC

[maven] branch MNG-7182 created (now 654c93b)

This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a change to branch MNG-7182
in repository https://gitbox.apache.org/repos/asf/maven.git.


      at 654c93b  Fix entity replacement

This branch includes the following new commits:

     new f833068  Use the MX xpp parser instead of a STAX transformation
     new 8559fcc  Fix minor issues after review
     new f2c5b92  Avoid changing parameter value
     new 654c93b  Fix entity replacement

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[maven] 01/04: Use the MX xpp parser instead of a STAX transformation

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-7182
in repository https://gitbox.apache.org/repos/asf/maven.git

commit f8330689cc887a7f13271ebcf584fca76b1e23a8
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Jul 8 07:54:01 2021 +0200

    Use the MX xpp parser instead of a STAX transformation
---
 .../aether/ConsumerModelSourceTransformer.java     |  97 +---
 .../DefaultRepositorySystemSessionFactory.java     |  30 +-
 .../building/AbstractModelSourceTransformer.java   | 205 --------
 .../building/BuildModelSourceTransformer.java      |  53 +-
 .../building/DefaultBuildPomXMLFilterFactory.java  |   6 +-
 .../building/DefaultModelSourceTransformer.java    |  10 +-
 .../model/building/ModelSourceTransformer.java     |   8 +-
 .../apache/maven/model/io/DefaultModelReader.java  |  87 ++--
 .../DefaultInheritanceAssemblerTest.java           |  15 +-
 maven-model-transform/pom.xml                      |   4 +
 .../model/transform/AbstractEventXMLFilter.java    | 289 -----------
 .../model/transform/BuildToRawPomXMLFilter.java    |  58 ---
 .../transform/BuildToRawPomXMLFilterFactory.java   |  64 +--
 .../transform/BuildToRawPomXMLFilterListener.java  |  42 --
 .../maven/model/transform/CiFriendlyXMLFilter.java |  70 +--
 .../maven/model/transform/DependencyKey.java       |  92 ----
 .../maven/model/transform/FastForwardFilter.java   |  97 ++--
 .../maven/model/transform/ModulesXMLFilter.java    |  82 +--
 .../maven/model/transform/ParentXMLFilter.java     | 226 ++++-----
 .../model/transform/RawToConsumerPomXMLFilter.java |  62 ---
 .../RawToConsumerPomXMLFilterFactory.java          |  19 +-
 .../transform/ReactorDependencyXMLFilter.java      | 186 +++----
 .../model/transform/RelativePathXMLFilter.java     | 102 ++--
 .../model/transform/pull/BufferingParser.java      | 563 +++++++++++++++++++++
 .../model/transform/pull/NodeBufferingParser.java  |  81 +++
 .../maven/model/transform/pull/XmlUtils.java       | 132 +++++
 .../model/transform/sax/AbstractSAXFilter.java     | 143 ------
 .../model/transform/sax/CommentRenormalizer.java   | 108 ----
 .../maven/model/transform/sax/Factories.java       |  79 ---
 .../apache/maven/model/transform/sax/SAXEvent.java |  34 --
 .../maven/model/transform/sax/SAXEventFactory.java | 144 ------
 .../maven/model/transform/sax/SAXEventUtils.java   |  49 --
 .../model/transform/AbstractXMLFilterTests.java    | 180 +------
 .../model/transform/CiFriendlyXMLFilterTest.java   |  24 +-
 .../model/transform/ConsumerPomXMLFilterTest.java  |  29 +-
 .../model/transform/ModulesXMLFilterTest.java      |  14 +-
 .../maven/model/transform/ParentXMLFilterTest.java | 115 +++--
 .../transform/ReactorDependencyXMLFilterTest.java  |  32 +-
 .../model/transform/RelativePathXMLFilterTest.java |   9 +-
 .../model/transform/sax/ChainedFilterTest.java     | 148 ------
 .../transform/sax/CommentRenormalizerTest.java     |  64 ---
 .../model/transform/sax/SAXEventUtilsTest.java     |  41 --
 42 files changed, 1276 insertions(+), 2617 deletions(-)

diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java b/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
index b720acb..c1e1144 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
@@ -23,91 +23,30 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.function.Consumer;
 
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-
-import org.apache.maven.model.building.AbstractModelSourceTransformer;
 import org.apache.maven.model.building.DefaultBuildPomXMLFilterFactory;
 import org.apache.maven.model.building.TransformerContext;
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.apache.maven.xml.internal.DefaultConsumerPomXMLFilterFactory;
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
-
-class ConsumerModelSourceTransformer extends AbstractModelSourceTransformer
+import org.apache.maven.model.transform.RawToConsumerPomXMLFilterFactory;
+import org.apache.maven.model.transform.pull.XmlUtils;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.xml.XmlStreamReader;
+import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
+import org.codehaus.plexus.util.xml.pull.MXParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+class ConsumerModelSourceTransformer
 {
-    @Override
-    protected AbstractSAXFilter getSAXFilter( Path pomFile,
-                                              TransformerContext context,
-                                              Consumer<LexicalHandler> lexicalHandlerConsumer )
-        throws TransformerConfigurationException, SAXException, ParserConfigurationException
-    {
-        return new DefaultConsumerPomXMLFilterFactory( new DefaultBuildPomXMLFilterFactory( context,
-                                                                        lexicalHandlerConsumer, true ) ).get( pomFile );
-    }
-
-    /**
-     * This transformer will ensure that encoding and version are kept.
-     * However, it cannot prevent:
-     * <ul>
-     *   <li>attributes will be on one line</li>
-     *   <li>Unnecessary whitespace before the rootelement will be removed</li>
-     * </ul>
-     */
-    @Override
-    protected TransformerHandler getTransformerHandler( Path pomFile )
-        throws IOException, org.apache.maven.model.building.TransformerException
+    public InputStream transform( Path pomFile, TransformerContext context )
+            throws IOException, XmlPullParserException
     {
-        final TransformerHandler transformerHandler;
-
-        final SAXTransformerFactory transformerFactory = getTransformerFactory();
-
-        // Keep same encoding+version
-        try ( InputStream input = Files.newInputStream( pomFile ) )
-        {
-            XMLStreamReader streamReader =
-                XMLInputFactory.newFactory().createXMLStreamReader( input );
-
-            transformerHandler = transformerFactory.newTransformerHandler();
-
-            final String encoding = streamReader.getCharacterEncodingScheme();
-            final String version = streamReader.getVersion();
-
-            Transformer transformer = transformerHandler.getTransformer();
-            transformer.setOutputProperty( OutputKeys.METHOD, "xml" );
-            if ( encoding == null && version == null )
-            {
-                transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );
-            }
-            else
-            {
-                transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "no" );
+        XmlStreamReader reader = ReaderFactory.newXmlReader( Files.newInputStream( pomFile ) );
+        XmlPullParser parser = new MXParser( EntityReplacementMap.defaultEntityReplacementMap );
+        parser.setInput( reader );
+        parser = new RawToConsumerPomXMLFilterFactory( new DefaultBuildPomXMLFilterFactory( context, true ) )
+                .get( parser, pomFile );
 
-                if ( encoding != null )
-                {
-                    transformer.setOutputProperty( OutputKeys.ENCODING, encoding );
-                }
-                if ( version != null )
-                {
-                    transformer.setOutputProperty( OutputKeys.VERSION, version );
-                }
-            }
-        }
-        catch ( XMLStreamException | TransformerConfigurationException e )
-        {
-            throw new org.apache.maven.model.building.TransformerException(
-                               "Failed to detect XML encoding and version", e );
-        }
-        return transformerHandler;
+        return XmlUtils.writeDocument( reader, parser );
     }
 
 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
index c419f17..c36451a 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
@@ -19,6 +19,19 @@ package org.apache.maven.internal.aether;
  * under the License.
  */
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.bridge.MavenRepositorySystem;
@@ -26,7 +39,6 @@ import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.feature.Features;
 import org.apache.maven.model.building.TransformerContext;
-import org.apache.maven.model.building.TransformerException;
 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
 import org.apache.maven.settings.Mirror;
 import org.apache.maven.settings.Proxy;
@@ -38,6 +50,7 @@ import org.apache.maven.settings.crypto.SettingsDecryptionResult;
 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 import org.eclipse.aether.ConfigurationProperties;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.RepositorySystem;
@@ -58,19 +71,6 @@ import org.eclipse.aether.util.repository.DefaultProxySelector;
 import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
 import org.eclipse.sisu.Nullable;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Properties;
-
 /**
  * @since 3.3.0
  */
@@ -302,7 +302,7 @@ public class DefaultRepositorySystemSessionFactory
                     {
                         return new ConsumerModelSourceTransformer().transform( pomFile.toPath(), context );
                     }
-                    catch ( TransformerException e )
+                    catch ( XmlPullParserException e )
                     {
                         throw new TransformException( e );
                     }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
index dba9294..3ea1dbf 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
@@ -19,35 +19,6 @@ package org.apache.maven.model.building;
  * under the License.
  */
 
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Consumer;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamResult;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.apache.maven.model.transform.sax.CommentRenormalizer;
-import org.apache.maven.model.transform.sax.Factories;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.ext.LexicalHandler;
-
 /**
  * Offers a transformation implementation based on PipelineStreams.
  * Subclasses are responsible for providing the right SAXFilter.
@@ -58,181 +29,5 @@ import org.xml.sax.ext.LexicalHandler;
 public abstract class AbstractModelSourceTransformer
     implements ModelSourceTransformer
 {
-    private static final AtomicInteger TRANSFORM_THREAD_COUNTER = new AtomicInteger();
-
-    private final TransformerFactory transformerFactory = Factories.newTransformerFactory();
-
-    protected abstract AbstractSAXFilter getSAXFilter( Path pomFile,
-                                                       TransformerContext context,
-                                                       Consumer<LexicalHandler> lexicalHandlerConsumer )
-        throws TransformerConfigurationException, SAXException, ParserConfigurationException;
-
-    protected OutputStream filterOutputStream( OutputStream outputStream, Path pomFile )
-    {
-        return outputStream;
-    }
-
-    public SAXTransformerFactory getTransformerFactory()
-    {
-        return ( SAXTransformerFactory ) transformerFactory;
-    }
-
-    protected TransformerHandler getTransformerHandler( Path pomFile )
-        throws IOException, org.apache.maven.model.building.TransformerException
-    {
-        return null;
-    }
-
-    @Override
-    public final InputStream transform( Path pomFile, TransformerContext context )
-        throws IOException, org.apache.maven.model.building.TransformerException
-    {
-        final TransformerHandler transformerHandler = getTransformerHandler( pomFile );
-
-        final PipedOutputStream pout = new PipedOutputStream();
-        OutputStream out = filterOutputStream( pout, pomFile );
-
-        final javax.xml.transform.Result result;
-        final Consumer<LexicalHandler> lexConsumer;
-        if ( transformerHandler == null )
-        {
-            result = new StreamResult( out );
-            lexConsumer = null;
-        }
-        else
-        {
-            result = new SAXResult( transformerHandler );
-            lexConsumer = l -> ( (SAXResult) result ).setLexicalHandler( new CommentRenormalizer( l ) );
-            transformerHandler.setResult( new StreamResult( out ) );
-        }
-
-        final AbstractSAXFilter filter;
-        try
-        {
-            filter = getSAXFilter( pomFile, context, lexConsumer );
-            filter.setLexicalHandler( transformerHandler );
-            // By default errors are written to stderr.
-            // Hence set custom errorHandler to reduce noice
-            filter.setErrorHandler( new ErrorHandler()
-            {
-                @Override
-                public void warning( SAXParseException exception )
-                    throws SAXException
-                {
-                    throw exception;
-                }
-
-                @Override
-                public void fatalError( SAXParseException exception )
-                    throws SAXException
-                {
-                    throw exception;
-                }
-
-                @Override
-                public void error( SAXParseException exception )
-                    throws SAXException
-                {
-                    throw exception;
-                }
-            } );
-        }
-        catch ( TransformerConfigurationException | SAXException | ParserConfigurationException e )
-        {
-            throw new org.apache.maven.model.building.TransformerException( e );
-        }
-
-        final SAXSource transformSource =
-            new SAXSource( filter, new org.xml.sax.InputSource( Files.newInputStream( pomFile ) ) );
-
-        IOExceptionHandler eh = new IOExceptionHandler();
-
-        // Ensure pipedStreams are connected before the transformThread starts!!
-        final PipedInputStream pipedInputStream = new PipedInputStream( pout );
-
-        Thread transformThread = new Thread( () ->
-        {
-            try ( PipedOutputStream pos = pout )
-            {
-                transformerFactory.newTransformer().transform( transformSource, result );
-            }
-            catch ( TransformerException | IOException e )
-            {
-                eh.uncaughtException( Thread.currentThread(), e );
-            }
-        }, "TransformThread-" + TRANSFORM_THREAD_COUNTER.incrementAndGet() );
-        transformThread.setUncaughtExceptionHandler( eh );
-        transformThread.setDaemon( true );
-        transformThread.start();
-
-        return new ThreadAwareInputStream( pipedInputStream, eh );
-    }
-
-    private static class IOExceptionHandler
-        implements Thread.UncaughtExceptionHandler, AutoCloseable
-    {
-        private volatile Throwable cause;
-
-        @Override
-        public void uncaughtException( Thread t, Throwable e )
-        {
-            try
-            {
-                throw e;
-            }
-            catch ( TransformerException | IOException | RuntimeException | Error allGood )
-            {
-                // all good
-                this.cause = e;
-            }
-            catch ( Throwable notGood )
-            {
-                throw new AssertionError( "Unexpected Exception", e );
-            }
-        }
-
-        @Override
-        public void close()
-            throws IOException
-        {
-            if ( cause != null )
-            {
-                try
-                {
-                    throw cause;
-                }
-                catch ( IOException | RuntimeException | Error e )
-                {
-                    throw e;
-                }
-                catch ( Throwable t )
-                {
-                    // Any checked exception
-                    throw new RuntimeException( "Failed to transform pom", t );
-                }
-            }
-        }
-    }
-
-    private class ThreadAwareInputStream
-        extends FilterInputStream
-    {
-        final IOExceptionHandler h;
-
-        protected ThreadAwareInputStream( InputStream in, IOExceptionHandler h )
-        {
-            super( in );
-            this.h = h;
-        }
 
-        @Override
-        public void close()
-            throws IOException
-        {
-            try ( IOExceptionHandler eh = h )
-            {
-                super.close();
-            }
-        }
-    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
index 699a009..9da284b 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
@@ -19,24 +19,14 @@ package org.apache.maven.model.building;
  * under the License.
  */
 
-import java.io.FilterOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.nio.file.Path;
-import java.util.function.Consumer;
 
-import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
 
 import org.apache.maven.model.transform.BuildToRawPomXMLFilterFactory;
-import org.apache.maven.model.transform.BuildToRawPomXMLFilterListener;
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.eclipse.sisu.Nullable;
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  * ModelSourceTransformer for the build pom
@@ -46,44 +36,15 @@ import org.xml.sax.ext.LexicalHandler;
  */
 @Named
 @Singleton
-class BuildModelSourceTransformer extends AbstractModelSourceTransformer
+class BuildModelSourceTransformer implements ModelSourceTransformer
 {
-    @Inject
-    @Nullable
-    private BuildToRawPomXMLFilterListener xmlFilterListener;
-
-    protected AbstractSAXFilter getSAXFilter( Path pomFile,
-                                              TransformerContext context,
-                                              Consumer<LexicalHandler> lexicalHandlerConsumer )
-        throws TransformerConfigurationException, SAXException, ParserConfigurationException
+    @Override
+    public XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
+            throws IOException, TransformerException
     {
         BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory =
-            new DefaultBuildPomXMLFilterFactory( context, lexicalHandlerConsumer, false );
-
-        return buildPomXMLFilterFactory.get( pomFile );
-    }
+                new DefaultBuildPomXMLFilterFactory( context, false );
 
-    @Override
-    protected OutputStream filterOutputStream( OutputStream outputStream, Path pomFile )
-    {
-        OutputStream out;
-        if ( xmlFilterListener != null )
-        {
-            out = new FilterOutputStream( outputStream )
-            {
-                @Override
-                public void write( byte[] b, int off, int len )
-                    throws IOException
-                {
-                    super.write( b, off, len );
-                    xmlFilterListener.write( pomFile, b, off, len );
-                }
-            };
-        }
-        else
-        {
-            out = outputStream;
-        }
-        return out;
+        return buildPomXMLFilterFactory.get( parser, pomFile );
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
index 906584d..3633a45 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
@@ -23,13 +23,11 @@ package org.apache.maven.model.building;
 import java.nio.file.Path;
 import java.util.Optional;
 import java.util.function.BiFunction;
-import java.util.function.Consumer;
 import java.util.function.Function;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.transform.BuildToRawPomXMLFilterFactory;
 import org.apache.maven.model.transform.RelativeProject;
-import org.xml.sax.ext.LexicalHandler;
 
 /**
  * A BuildPomXMLFilterFactory which is context aware
@@ -44,14 +42,12 @@ public class DefaultBuildPomXMLFilterFactory extends BuildToRawPomXMLFilterFacto
     /**
      *
      * @param context a set of data to extract values from as required for the build pom
-     * @param lexicalHandlerConsumer the lexical handler consumer
      * @param consume {@code true} if this factory is being used for creating the consumer pom, otherwise {@code false}
      */
     public DefaultBuildPomXMLFilterFactory( TransformerContext context,
-                                            Consumer<LexicalHandler> lexicalHandlerConsumer,
                                             boolean consume )
     {
-        super( lexicalHandlerConsumer, consume );
+        super( consume );
         this.context = context;
     }
 
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelSourceTransformer.java
index 7c57f30..e6e4073 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelSourceTransformer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelSourceTransformer.java
@@ -20,10 +20,10 @@ package org.apache.maven.model.building;
  */
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
 import java.nio.file.Path;
 
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+
 /**
  * Default ModelSourceTransformer, provides pomFile as inputStream and ignores the context
  *
@@ -34,10 +34,10 @@ public class DefaultModelSourceTransformer implements ModelSourceTransformer
 {
 
     @Override
-    public InputStream transform( Path pomFile, TransformerContext context )
-        throws IOException, TransformerException
+    public XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
+            throws IOException, TransformerException
     {
-        return Files.newInputStream( pomFile );
+        return parser;
     }
 
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java
index a2556ce..a2504ef 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java
@@ -20,16 +20,18 @@ package org.apache.maven.model.building;
  */
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.nio.file.Path;
 
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+
 /**
  * The ModelSourceTransformer is a way to transform the local pom while streaming the input.
  *
- * The {@link #transform(Path, TransformerContext)} method uses a Path on purpose, to ensure the
+ * The {@link #transform(XmlPullParser, Path, TransformerContext)} method uses a Path on purpose, to ensure the
  * local pom is the the original source.
  *
  * @author Robert Scholte
+ * @author Guillaume Nodet
  * @since 4.0.0
  */
 public interface ModelSourceTransformer
@@ -42,6 +44,6 @@ public interface ModelSourceTransformer
      * @throws IOException if an I/O error occurs
      * @throws TransformerException if the transformation fails
      */
-    InputStream transform( Path pomFile, TransformerContext context )
+    XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
         throws IOException, TransformerException;
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
index 1d8b264..fd4cb8a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
@@ -20,10 +20,12 @@ package org.apache.maven.model.io;
  */
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.file.Path;
 import java.util.Map;
 import java.util.Objects;
 
@@ -35,11 +37,13 @@ import org.apache.maven.model.InputSource;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelSourceTransformer;
 import org.apache.maven.model.building.TransformerContext;
-import org.apache.maven.model.building.TransformerException;
 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
 import org.apache.maven.model.io.xpp3.MavenXpp3ReaderEx;
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.xml.XmlStreamReader;
+import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
+import org.codehaus.plexus.util.xml.pull.MXParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 /**
@@ -66,28 +70,9 @@ public class DefaultModelReader
     {
         Objects.requireNonNull( input, "input cannot be null" );
 
-        TransformerContext context = getTransformerContext( options );
-
-        final InputStream is;
-        if ( context == null )
-        {
-            is = new FileInputStream( input );
-        }
-        else
-        {
-            try
-            {
-                is = transformer.transform( input.toPath(), context );
-            }
-            catch ( TransformerException e )
-            {
-                throw new IOException( "Failed to transform " + input,  e );
-            }
-        }
-
-        try ( InputStream in = is )
+        try ( XmlStreamReader in = ReaderFactory.newXmlReader( input ) )
         {
-            Model model = read( is, options );
+            Model model = read( in, input.toPath(), options );
 
             model.setPomFile( input );
 
@@ -103,7 +88,7 @@ public class DefaultModelReader
 
         try ( Reader in = input )
         {
-            return read( in, isStrict( options ), getSource( options ) );
+            return read( in, null, options );
         }
     }
 
@@ -115,7 +100,7 @@ public class DefaultModelReader
 
         try ( XmlStreamReader in = ReaderFactory.newXmlReader( input ) )
         {
-            return read( in, isStrict( options ), getSource( options ) );
+            return read( in, null, options );
         }
     }
 
@@ -137,24 +122,66 @@ public class DefaultModelReader
         return (TransformerContext) value;
     }
 
-    private Model read( Reader reader, boolean strict, InputSource source )
+    private Model read( Reader reader, Path pomFile, Map<String, ?> options )
         throws IOException
     {
         try
         {
-            if ( source != null )
+            XmlPullParser parser = new MXParser( EntityReplacementMap.defaultEntityReplacementMap );
+            parser.setInput( reader );
+
+            TransformerContext context = getTransformerContext( options );
+            if ( context != null )
+            {
+                parser = transformer.transform( parser, pomFile, context );
+            }
+
+            // TODO: avoid or at least cache reflection data
+            InputSource source = getSource( options );
+            boolean strict = isStrict( options );
+            try
             {
-                return new MavenXpp3ReaderEx().read( reader, strict, source );
+                if ( source != null )
+                {
+                    MavenXpp3ReaderEx mr = new MavenXpp3ReaderEx();
+                    Method readMethod = mr.getClass().getDeclaredMethod( "read",
+                            XmlPullParser.class, boolean.class, InputSource.class );
+                    readMethod.setAccessible( true );
+                    Object model = readMethod.invoke( mr, parser, strict, source );
+                    return (Model) model;
+                }
+                else
+                {
+                    MavenXpp3Reader mr = new MavenXpp3Reader();
+                    Method readMethod = mr.getClass().getDeclaredMethod( "read",
+                            XmlPullParser.class, boolean.class );
+                    readMethod.setAccessible( true );
+                    Object model = readMethod.invoke( mr, parser, strict );
+                    return (Model) model;
+                }
             }
-            else
+            catch ( InvocationTargetException e )
             {
-                return new MavenXpp3Reader().read( reader, strict );
+                Throwable cause = e.getCause();
+                if ( cause instanceof Exception )
+                {
+                    throw ( Exception ) cause;
+                }
+                throw e;
             }
         }
         catch ( XmlPullParserException e )
         {
             throw new ModelParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
         }
+        catch ( IOException e )
+        {
+            throw e;
+        }
+        catch ( Exception e )
+        {
+            throw new IOException( "Unable to transform pom", e );
+        }
     }
 
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
index b499fc0..d219638 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
@@ -22,22 +22,16 @@ package org.apache.maven.model.inheritance;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
-import java.util.function.Consumer;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.AbstractModelSourceTransformer;
 import org.apache.maven.model.building.SimpleProblemCollector;
 import org.apache.maven.model.building.TransformerContext;
+import org.apache.maven.model.building.TransformerException;
 import org.apache.maven.model.io.DefaultModelReader;
 import org.apache.maven.model.io.DefaultModelWriter;
 import org.apache.maven.model.io.ModelWriter;
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.xmlunit.matchers.CompareMatcher;
@@ -65,9 +59,8 @@ public class DefaultInheritanceAssemblerTest
         reader.setTransformer( new AbstractModelSourceTransformer()
         {
             @Override
-            protected AbstractSAXFilter getSAXFilter( Path pomFile, TransformerContext context,
-                                                      Consumer<LexicalHandler> lexicalHandlerConsumer )
-                throws TransformerConfigurationException, SAXException, ParserConfigurationException
+            public XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
+                    throws IOException, TransformerException
             {
                 return null;
             }
diff --git a/maven-model-transform/pom.xml b/maven-model-transform/pom.xml
index 2839d52..5024085 100644
--- a/maven-model-transform/pom.xml
+++ b/maven-model-transform/pom.xml
@@ -33,6 +33,10 @@ under the License.
 
   <dependencies>
     <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter-params</artifactId>
       <scope>test</scope>
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/AbstractEventXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/AbstractEventXMLFilter.java
deleted file mode 100644
index 7264145..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/AbstractEventXMLFilter.java
+++ /dev/null
@@ -1,289 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Queue;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.apache.maven.model.transform.sax.SAXEvent;
-import org.apache.maven.model.transform.sax.SAXEventFactory;
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-
-/**
- * Builds up a list of SAXEvents, which will be executed with {@link #executeEvents()}
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-abstract class AbstractEventXMLFilter extends AbstractSAXFilter
-{
-    private Queue<SAXEvent> saxEvents = new ArrayDeque<>();
-
-    private SAXEventFactory eventFactory;
-
-    // characters BEFORE startElement must get state of startingElement
-    // this way removing based on state keeps correct formatting
-    private List<SAXEvent> charactersSegments = new ArrayList<>();
-
-    private boolean lockCharacters = false;
-
-    protected abstract boolean isParsing();
-
-    protected abstract String getState();
-
-    protected boolean acceptEvent( String state )
-    {
-        return true;
-    }
-
-    AbstractEventXMLFilter()
-    {
-        super();
-    }
-
-    AbstractEventXMLFilter( AbstractSAXFilter parent )
-    {
-        super( parent );
-    }
-
-    private SAXEventFactory getEventFactory()
-    {
-        if ( eventFactory == null )
-        {
-            eventFactory = SAXEventFactory.newInstance( getContentHandler(), getLexicalHandler() );
-        }
-        return eventFactory;
-    }
-
-    private void processEvent( final SAXEvent event )
-                    throws SAXException
-    {
-        if ( isParsing() )
-        {
-            final String eventState = getState();
-
-            if ( !lockCharacters )
-            {
-                charactersSegments.stream().forEach( e ->
-                {
-                    saxEvents.add( () ->
-                    {
-                        if ( acceptEvent( eventState ) )
-                        {
-                            e.execute();
-                        }
-                    } );
-                } );
-                charactersSegments.clear();
-            }
-
-            saxEvents.add( () ->
-            {
-                if ( acceptEvent( eventState ) )
-                {
-                    event.execute();
-                }
-            } );
-        }
-        else
-        {
-            event.execute();
-        }
-    }
-
-    /**
-     * Should be used to include extra events before a closing element.
-     * This is a lightweight solution to keep the correct indentation.
-     */
-    protected Includer include()
-    {
-        this.lockCharacters = true;
-
-        return () -> lockCharacters = false;
-    }
-
-    protected final void executeEvents() throws SAXException
-    {
-        final String eventState = getState();
-        charactersSegments.stream().forEach( e ->
-        {
-            saxEvents.add( () ->
-            {
-                if ( acceptEvent( eventState ) )
-                {
-                    e.execute();
-                }
-            } );
-        } );
-        charactersSegments.clear();
-
-        // not with streams due to checked SAXException
-        while ( !saxEvents.isEmpty() )
-        {
-            saxEvents.poll().execute();
-        }
-    }
-
-    @Override
-    public void setDocumentLocator( Locator locator )
-    {
-        try
-        {
-            processEvent( getEventFactory().setDocumentLocator( locator ) );
-        }
-        catch ( SAXException e )
-        {
-            // noop, setDocumentLocator can never throw a SAXException
-        }
-    }
-
-    @Override
-    public void startDocument() throws SAXException
-    {
-        processEvent( getEventFactory().startDocument() );
-    }
-
-    @Override
-    public void endDocument() throws SAXException
-    {
-        processEvent( getEventFactory().endDocument() );
-    }
-
-    @Override
-    public void startPrefixMapping( String prefix, String uri ) throws SAXException
-    {
-        processEvent( getEventFactory().startPrefixMapping( prefix, uri ) );
-    }
-
-    @Override
-    public void endPrefixMapping( String prefix ) throws SAXException
-    {
-        processEvent( getEventFactory().endPrefixMapping( prefix ) );
-    }
-
-    @Override
-    public void startElement( String uri, String localName, String qName, Attributes atts ) throws SAXException
-    {
-        processEvent( getEventFactory().startElement( uri, localName, qName, atts ) );
-    }
-
-    @Override
-    public void endElement( String uri, String localName, String qName ) throws SAXException
-    {
-        processEvent( getEventFactory().endElement( uri, localName, qName ) );
-    }
-
-    @Override
-    public void characters( char[] ch, int start, int length ) throws SAXException
-    {
-        if ( lockCharacters )
-        {
-            processEvent( getEventFactory().characters( ch, start, length ) );
-        }
-        else if ( isParsing() )
-        {
-            this.charactersSegments.add( getEventFactory().characters( ch, start, length ) );
-        }
-        else
-        {
-            super.characters( ch, start, length );
-        }
-    }
-
-    @Override
-    public void ignorableWhitespace( char[] ch, int start, int length ) throws SAXException
-    {
-        processEvent( getEventFactory().ignorableWhitespace( ch, start, length ) );
-    }
-
-    @Override
-    public void processingInstruction( String target, String data ) throws SAXException
-    {
-        processEvent( getEventFactory().processingInstruction( target, data ) );
-    }
-
-    @Override
-    public void skippedEntity( String name ) throws SAXException
-    {
-        processEvent( getEventFactory().skippedEntity( name ) );
-    }
-
-    @Override
-    public void startDTD( String name, String publicId, String systemId ) throws SAXException
-    {
-        processEvent( getEventFactory().startCDATA() );
-    }
-
-    @Override
-    public void endDTD() throws SAXException
-    {
-        processEvent( getEventFactory().endDTD() );
-    }
-
-    @Override
-    public void startEntity( String name ) throws SAXException
-    {
-        processEvent( getEventFactory().startEntity( name ) );
-    }
-
-    @Override
-    public void endEntity( String name ) throws SAXException
-    {
-        processEvent( getEventFactory().endEntity( name ) );
-    }
-
-    @Override
-    public void startCDATA()
-        throws SAXException
-    {
-        processEvent( getEventFactory().startCDATA() );
-    }
-
-    @Override
-    public void endCDATA()
-        throws SAXException
-    {
-        processEvent( getEventFactory().endCDATA() );
-    }
-
-    @Override
-    public void comment( char[] ch, int start, int length )
-        throws SAXException
-    {
-        processEvent( getEventFactory().comment( ch, start, length ) );
-    }
-
-    /**
-     * AutoCloseable with a close method that doesn't throw an exception
-     *
-     * @author Robert Scholte
-     *
-     */
-    @FunctionalInterface
-    protected interface Includer extends AutoCloseable
-    {
-        void close();
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilter.java
deleted file mode 100644
index 8cc392f..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.xml.sax.XMLReader;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-
-/**
- * Filter to adjust pom on filesystem before being processed for effective pom.
- * There should only be 1 BuildToRawPomXMLFilter, so the same is being used by both
- * org.apache.maven.model.building.DefaultModelBuilder.transformData(InputStream) and
- * org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory.newFileTransformerManager()
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class BuildToRawPomXMLFilter extends AbstractSAXFilter
-{
-    BuildToRawPomXMLFilter()
-    {
-        super();
-    }
-
-    BuildToRawPomXMLFilter( AbstractSAXFilter parent )
-    {
-        super( parent );
-    }
-
-    /**
-     * Don't allow overwriting parent
-     */
-    @Override
-    public final void setParent( XMLReader parent )
-    {
-        if ( getParent() == null )
-        {
-            super.setParent( parent );
-        }
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
index 3531e2b..4673102 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
@@ -22,17 +22,9 @@ package org.apache.maven.model.transform;
 import java.nio.file.Path;
 import java.util.Optional;
 import java.util.function.BiFunction;
-import java.util.function.Consumer;
 import java.util.function.Function;
 
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.apache.maven.model.transform.sax.Factories;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  * Base implementation for providing the BuildToRawPomXML.
@@ -44,74 +36,40 @@ public class BuildToRawPomXMLFilterFactory
 {
     private final boolean consume;
 
-    private final Consumer<LexicalHandler> lexicalHandlerConsumer;
-
-    public BuildToRawPomXMLFilterFactory( Consumer<LexicalHandler> lexicalHandlerConsumer )
+    public BuildToRawPomXMLFilterFactory()
     {
-        this( lexicalHandlerConsumer, false );
+        this( false );
     }
 
-    public BuildToRawPomXMLFilterFactory( Consumer<LexicalHandler> lexicalHandlerConsumer, boolean consume )
+    public BuildToRawPomXMLFilterFactory( boolean consume )
     {
-        this.lexicalHandlerConsumer = lexicalHandlerConsumer;
         this.consume = consume;
     }
 
     /**
      *
      * @param projectFile will be used by ConsumerPomXMLFilter to get the right filter
-     * @throws SAXException
-     * @throws ParserConfigurationException
-     * @throws TransformerConfigurationException
      */
-    public final BuildToRawPomXMLFilter get( Path projectFile )
-        throws SAXException, ParserConfigurationException, TransformerConfigurationException
-    {
-        AbstractSAXFilter parent = new AbstractSAXFilter();
-        parent.setParent( getXMLReader() );
-        if ( lexicalHandlerConsumer != null )
-        {
-            lexicalHandlerConsumer.accept( parent );
-        }
+    public final XmlPullParser get( XmlPullParser parser, Path projectFile )
 
+    {
         if ( getDependencyKeyToVersionMapper() != null )
         {
-            ReactorDependencyXMLFilter reactorDependencyXMLFilter =
-                new ReactorDependencyXMLFilter( getDependencyKeyToVersionMapper() );
-            reactorDependencyXMLFilter.setParent( parent );
-            parent.setLexicalHandler( reactorDependencyXMLFilter );
-            parent = reactorDependencyXMLFilter;
+            parser = new ReactorDependencyXMLFilter( parser, getDependencyKeyToVersionMapper() );
         }
 
         if ( getRelativePathMapper() != null )
         {
-            ParentXMLFilter parentFilter = new ParentXMLFilter( getRelativePathMapper() );
-            parentFilter.setProjectPath( projectFile.getParent() );
-            parentFilter.setParent( parent );
-            parent.setLexicalHandler( parentFilter );
-            parent = parentFilter;
+            parser = new ParentXMLFilter( parser, getRelativePathMapper(), projectFile.getParent() );
         }
 
-        CiFriendlyXMLFilter ciFriendlyFilter = new CiFriendlyXMLFilter( consume );
+        CiFriendlyXMLFilter ciFriendlyFilter = new CiFriendlyXMLFilter( parser, consume );
         getChangelist().ifPresent( ciFriendlyFilter::setChangelist  );
         getRevision().ifPresent( ciFriendlyFilter::setRevision );
         getSha1().ifPresent( ciFriendlyFilter::setSha1 );
+        parser = ciFriendlyFilter;
 
-        if ( ciFriendlyFilter.isSet() )
-        {
-            ciFriendlyFilter.setParent( parent );
-            parent.setLexicalHandler( ciFriendlyFilter );
-            parent = ciFriendlyFilter;
-        }
-
-        return new BuildToRawPomXMLFilter( parent );
-    }
-
-    private XMLReader getXMLReader() throws SAXException, ParserConfigurationException
-    {
-        XMLReader xmlReader = Factories.newXMLReader();
-        xmlReader.setFeature( "http://xml.org/sax/features/namespaces", true );
-        return xmlReader;
+        return parser;
     }
 
     /**
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterListener.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterListener.java
deleted file mode 100644
index ff9cfb6..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterListener.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.nio.file.Path;
-
-/**
- * Listener can be used to capture the result of the transformation of build to raw POM.
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-@FunctionalInterface
-public interface BuildToRawPomXMLFilterListener
-{
-    /**
-     * Captures the result of the XML transformation
-     *
-     * @param pomFile the original to being transformed
-     * @param b the byte array
-     * @param off the offset
-     * @param len the length
-     */
-    void write( Path pomFile, byte[] b, int off, int len );
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/CiFriendlyXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/CiFriendlyXMLFilter.java
index 1a38a98..f981a8f 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/CiFriendlyXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/CiFriendlyXMLFilter.java
@@ -19,37 +19,29 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
+import java.util.List;
 import java.util.function.Function;
 
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
+import org.apache.maven.model.transform.pull.NodeBufferingParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  * Resolves all ci-friendly properties occurrences between version-tags
  *
  * @author Robert Scholte
+ * @author Guillaume Nodet
  * @since 4.0.0
  */
 class CiFriendlyXMLFilter
-    extends AbstractSAXFilter
+    extends NodeBufferingParser
 {
     private final boolean replace;
 
     private Function<String, String> replaceChain = Function.identity();
 
-    private String characters;
-
-    private boolean parseVersion;
-
-    CiFriendlyXMLFilter( boolean replace )
+    CiFriendlyXMLFilter( XmlPullParser xmlPullParser, boolean replace )
     {
-        this.replace = replace;
-    }
-
-    CiFriendlyXMLFilter( AbstractSAXFilter parent, boolean replace )
-    {
-        super( parent );
+        super( xmlPullParser, "version" );
         this.replace = replace;
     }
 
@@ -80,52 +72,16 @@ class CiFriendlyXMLFilter
     }
 
     @Override
-    public void characters( char[] ch, int start, int length )
-        throws SAXException
+    protected void process( List<Event> buffer )
     {
-        if ( parseVersion )
+        for ( Event event : buffer )
         {
-            this.characters = nullSafeAppend( characters, new String( ch, start, length ) );
-        }
-        else
-        {
-            super.characters( ch, start, length );
-        }
-    }
-
-    @Override
-    public void startElement( String uri, String localName, String qName, Attributes atts )
-        throws SAXException
-    {
-        if ( !parseVersion && "version".equals( localName ) )
-        {
-            parseVersion = true;
-        }
-
-        super.startElement( uri, localName, qName, atts );
-    }
-
-    @Override
-    public void endElement( String uri, String localName, String qName )
-        throws SAXException
-    {
-        if ( parseVersion )
-        {
-            // assuming this has the best performance
-            if ( replace && characters != null && characters.contains( "${" ) )
-            {
-                char[] ch = replaceChain.apply( characters ).toCharArray();
-                super.characters( ch, 0, ch.length );
-            }
-            else
+            if ( event.event == TEXT && replace && event.text.contains( "${" ) )
             {
-                char[] ch = characters.toCharArray();
-                super.characters( ch, 0, ch.length );
+                event.text = replaceChain.apply( event.text );
             }
-            characters = null;
-            parseVersion = false;
+            pushEvent( event );
         }
-
-        super.endElement( uri, localName, qName );
     }
+
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/DependencyKey.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/DependencyKey.java
deleted file mode 100644
index d114cc1..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/DependencyKey.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Objects;
-
-/**
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class DependencyKey
-{
-    private final String groupId;
-
-    private final String artifactId;
-
-    private final int hashCode;
-
-    public DependencyKey( String groupId, String artifactId )
-    {
-        this.groupId = groupId;
-        this.artifactId = artifactId;
-
-        this.hashCode = Objects.hash( artifactId, groupId );
-    }
-
-    public String getGroupId()
-    {
-        return groupId;
-    }
-
-    public String getArtifactId()
-    {
-        return artifactId;
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return hashCode;
-    }
-
-    @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
-            return true;
-        }
-        if ( obj == null )
-        {
-            return false;
-        }
-        if ( getClass() != obj.getClass() )
-        {
-            return false;
-        }
-
-        DependencyKey other = (DependencyKey) obj;
-
-        if ( !Objects.equals( artifactId, other.artifactId ) )
-        {
-            return false;
-        }
-        if ( !Objects.equals( groupId, other.groupId ) )
-        {
-            return false;
-        }
-
-        return true;
-    }
-
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
index ea0eb9f..c5c2171 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
@@ -19,23 +19,23 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
+import java.io.IOException;
 import java.util.ArrayDeque;
 import java.util.Deque;
 
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLFilter;
+import org.apache.maven.model.transform.pull.BufferingParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 /**
  * This filter will skip all following filters and write directly to the output.
  * Should be used in case of a DOM that should not be effected by other filters, even though the elements match
  *
  * @author Robert Scholte
+ * @author Guillaume Nodet
  * @since 4.0.0
  */
-class FastForwardFilter extends AbstractSAXFilter
+class FastForwardFilter extends BufferingParser
 {
     /**
      * DOM elements of pom
@@ -53,75 +53,50 @@ class FastForwardFilter extends AbstractSAXFilter
 
     private int domDepth = 0;
 
-    private ContentHandler originalHandler;
-
-    FastForwardFilter()
+    FastForwardFilter( XmlPullParser xmlPullParser )
     {
-        super();
-    }
-
-    FastForwardFilter( AbstractSAXFilter parent )
-    {
-        super( parent );
+        super( xmlPullParser );
     }
 
     @Override
-    public void startElement( String uri, String localName, String qName, Attributes atts )
-        throws SAXException
+    protected boolean accept() throws XmlPullParserException, IOException
     {
-        super.startElement( uri, localName, qName, atts );
-        if ( domDepth > 0 )
+        if ( xmlPullParser.getEventType() == START_TAG )
         {
-            domDepth++;
-        }
-        else
-        {
-            final String key = state.peek() + '.' + localName;
-            switch ( key )
+            String localName = xmlPullParser.getName();
+            if ( domDepth > 0 )
             {
-                case "execution.configuration":
-                case "plugin.configuration":
-                case "plugin.goals":
-                case "profile.reports":
-                case "project.reports":
-                case "reportSet.configuration":
-                    domDepth++;
-
-                    originalHandler = getContentHandler();
-
-                    ContentHandler outputContentHandler = getContentHandler();
-                    while ( outputContentHandler instanceof XMLFilter )
-                    {
-                        outputContentHandler = ( (XMLFilter) outputContentHandler ).getContentHandler();
-                    }
-                    setContentHandler( outputContentHandler );
-                    break;
-                default:
-                    break;
+                domDepth++;
             }
-            state.push( localName );
-        }
-    }
-
-    @Override
-    public void endElement( String uri, String localName, String qName )
-        throws SAXException
-    {
-        if ( domDepth > 0 )
-        {
-            domDepth--;
-
-            if ( domDepth == 0 )
+            else
             {
-                setContentHandler( originalHandler );
+                final String key = state.peek() + '/' + localName;
+                switch ( key )
+                {
+                    case "execution/configuration":
+                    case "plugin/configuration":
+                    case "plugin/goals":
+                    case "profile/reports":
+                    case "project/reports":
+                    case "reportSet/configuration":
+                        domDepth++;
+                        disable();
+                        break;
+                    default:
+                        break;
+                }
             }
+            state.add( localName );
         }
-        else
+        else if ( xmlPullParser.getEventType() == END_TAG )
         {
+            if ( --domDepth == 0 )
+            {
+                enable();
+            }
             state.pop();
         }
-        super.endElement( uri, localName, qName );
+        return true;
     }
 
-
 }
\ No newline at end of file
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModulesXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModulesXMLFilter.java
index 187fc78..4d3f94a 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModulesXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModulesXMLFilter.java
@@ -19,93 +19,29 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
+import java.util.List;
 
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
+import org.apache.maven.model.transform.pull.NodeBufferingParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  * Remove all modules, this is just buildtime information
  *
  * @author Robert Scholte
+ * @author Guillaume Nodet
  * @since 4.0.0
  */
 class ModulesXMLFilter
-    extends AbstractEventXMLFilter
+    extends NodeBufferingParser
 {
-    private boolean parsingModules;
-
-    private String state;
-
-    ModulesXMLFilter()
-    {
-        super();
-    }
-
-    ModulesXMLFilter( AbstractSAXFilter parent )
-    {
-        super( parent );
-    }
-
-    @Override
-    public void startElement( String uri, String localName, String qName, Attributes atts )
-        throws SAXException
-    {
-        if ( !parsingModules && "modules".equals( localName ) )
-        {
-            parsingModules = true;
-        }
-
-        if ( parsingModules )
-        {
-            state = localName;
-        }
-
-        super.startElement( uri, localName, qName, atts );
-    }
-
-    @Override
-    public void endElement( String uri, String localName, String qName )
-        throws SAXException
-    {
-        if ( parsingModules )
-        {
-            switch ( localName )
-            {
-                case "modules":
-                    executeEvents();
-
-                    parsingModules = false;
-                    break;
-                default:
-                    super.endElement( uri, localName, qName );
-                    break;
-            }
-        }
-        else
-        {
-            super.endElement( uri, localName, qName );
-        }
-
-        // for this simple structure resetting to modules it sufficient
-        state = "modules";
-    }
-
-    @Override
-    protected boolean isParsing()
+    ModulesXMLFilter( XmlPullParser xmlPullParser )
     {
-        return parsingModules;
+        super( xmlPullParser, "modules" );
     }
 
-    @Override
-    protected String getState()
+    protected void process( List<Event> buffer )
     {
-        return state;
+        // Do nothing, as we want to delete those nodes completely
     }
 
-    @Override
-    protected boolean acceptEvent( String state )
-    {
-        return false;
-    }
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
index 926222c..37ac28b 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
@@ -22,14 +22,13 @@ package org.apache.maven.model.transform;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-
+import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 
-import org.apache.maven.model.transform.sax.SAXEventUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
+import org.apache.maven.model.transform.pull.NodeBufferingParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  * <p>
@@ -40,167 +39,117 @@ import org.xml.sax.SAXException;
  * </p>
  *
  * @author Robert Scholte
+ * @author Guillaume Nodet
  * @since 4.0.0
  */
 class ParentXMLFilter
-    extends AbstractEventXMLFilter
+    extends NodeBufferingParser
 {
-    private boolean parsingParent;
-
-    // states
-    private String state;
-
-    // whiteSpace after <parent>, to be used to position <version>
-    private String parentWhitespace = "";
-
-    private String groupId;
-
-    private String artifactId;
-
-    private String relativePath;
-
-    private boolean hasVersion;
-
-    private boolean hasRelativePath;
-
-    private Optional<RelativeProject> resolvedParent;
 
     private final Function<Path, Optional<RelativeProject>> relativePathMapper;
 
-    private Path projectPath;
+    private final Path projectPath;
 
     /**
      * @param relativePathMapper
      */
-    ParentXMLFilter( Function<Path, Optional<RelativeProject>> relativePathMapper )
+    ParentXMLFilter( XmlPullParser parser,
+                     Function<Path, Optional<RelativeProject>> relativePathMapper, Path projectPath )
     {
+        super( parser, "parent" );
         this.relativePathMapper = relativePathMapper;
-    }
-
-    public void setProjectPath( Path projectPath )
-    {
         this.projectPath = projectPath;
     }
 
-    @Override
-    protected boolean isParsing()
-    {
-        return parsingParent;
-    }
-
-    @Override
-    protected String getState()
-    {
-        return state;
-    }
-
-    @Override
-    public void startElement( String uri, final String localName, String qName, Attributes atts )
-        throws SAXException
-    {
-        if ( !parsingParent && "parent".equals( localName ) )
-        {
-            parsingParent = true;
-        }
-
-        if ( parsingParent )
-        {
-            state = localName;
-
-            hasVersion |= "version".equals( localName );
-
-            // can be set to empty on purpose to enforce repository download
-            hasRelativePath |= "relativePath".equals( localName );
-        }
-
-        super.startElement( uri, localName, qName, atts );
-    }
-
-    @Override
-    public void characters( char[] ch, int start, int length )
-        throws SAXException
+    protected void process( List<Event> buffer )
     {
-        if ( parsingParent )
+        String tagName = null;
+        String groupId = null;
+        String artifactId = null;
+        String version = null;
+        String relativePath = null;
+        String whitespaceAfterParentStart = "";
+        boolean hasVersion = false;
+        boolean hasRelativePath = false;
+        for ( int i = 0; i < buffer.size(); i++ )
         {
-            final String eventState = state;
-
-            final String charSegment =  new String( ch, start, length );
-
-            switch ( eventState )
+            Event event = buffer.get( i );
+            if ( event.event == START_TAG )
             {
-                case "parent":
-                    parentWhitespace = nullSafeAppend( parentWhitespace, charSegment );
-                    break;
-                case "relativePath":
-                    relativePath = nullSafeAppend( relativePath, charSegment );
-                    break;
-                case "groupId":
-                    groupId = nullSafeAppend( groupId, charSegment );
-                    break;
-                case "artifactId":
-                    artifactId = nullSafeAppend( artifactId, charSegment );
-                    break;
-                default:
-                    break;
+                tagName = event.name;
+                hasVersion |= "version".equals( tagName );
+                hasRelativePath |= "relativePath".equals( tagName );
             }
-        }
-
-        super.characters( ch, start, length );
-    }
-
-    @Override
-    public void endElement( String uri, final String localName, String qName )
-        throws SAXException
-    {
-        if ( parsingParent )
-        {
-            switch ( localName )
+            else if ( event.event == TEXT )
             {
-                case "parent":
-                    if ( !hasVersion && ( !hasRelativePath || relativePath != null ) )
-                    {
-                        resolvedParent =
-                            resolveRelativePath( Paths.get( Objects.toString( relativePath, "../pom.xml" ) ) );
-                    }
-                    else
+                if ( event.text.matches( "\\s+" ) )
+                {
+                    if ( whitespaceAfterParentStart.isEmpty() )
                     {
-                        resolvedParent = Optional.empty();
+                        whitespaceAfterParentStart = event.text;
                     }
-
-                    if ( !hasVersion && resolvedParent.isPresent() )
-                    {
-                        try ( Includer i = super.include() )
-                        {
-                            super.characters( parentWhitespace.toCharArray(), 0,
-                                              parentWhitespace.length() );
-
-                            String versionQName = SAXEventUtils.renameQName( qName, "version" );
-
-                            super.startElement( uri, "version", versionQName, null );
-
-                            String resolvedParentVersion = resolvedParent.get().getVersion();
-
-                            super.characters( resolvedParentVersion.toCharArray(), 0,
-                                                          resolvedParentVersion.length() );
-
-                            super.endElement( uri, "version", versionQName );
-                        }
-                    }
-                    super.executeEvents();
-
-                    parsingParent = false;
-                    break;
-                default:
-                    // marker?
-                    break;
+                }
+                else if ( "groupId".equals( tagName ) )
+                {
+                    groupId = nullSafeAppend( groupId, event.text );
+                }
+                else if ( "artifactId".equals( tagName ) )
+                {
+                    artifactId = nullSafeAppend( artifactId, event.text );
+                }
+                else if ( "relativePath".equals( tagName ) )
+                {
+                    relativePath = nullSafeAppend( relativePath, event.text );
+                }
+                else if ( "version".equals( tagName ) )
+                {
+                    version = nullSafeAppend( version, event.text );
+                }
+            }
+            else if ( event.event == END_TAG && "parent".equals( event.name ) )
+            {
+                Optional<RelativeProject> resolvedParent;
+                if ( !hasVersion && ( !hasRelativePath || relativePath != null ) )
+                {
+                    Path relPath = Paths.get( Objects.toString( relativePath, "../pom.xml" ) );
+                    resolvedParent = resolveRelativePath( relPath, groupId, artifactId );
+                }
+                else
+                {
+                    resolvedParent = Optional.empty();
+                }
+                if ( !hasVersion && resolvedParent.isPresent() )
+                {
+                    int pos = buffer.get( i - 1 ).event == TEXT ? i - 1  : i;
+                    Event e = new Event();
+                    e.event = TEXT;
+                    e.text = whitespaceAfterParentStart;
+                    buffer.add( pos++, e );
+                    e = new Event();
+                    e.event = START_TAG;
+                    e.namespace = buffer.get( 0 ).namespace;
+                    e.prefix = buffer.get( 0 ).prefix;
+                    e.name = "version";
+                    buffer.add( pos++, e );
+                    e = new Event();
+                    e.event = TEXT;
+                    e.text = resolvedParent.get().getVersion();
+                    buffer.add( pos++, e );
+                    e = new Event();
+                    e.event = END_TAG;
+                    e.name = "version";
+                    e.namespace = buffer.get( 0 ).namespace;
+                    e.prefix = buffer.get( 0 ).prefix;
+                    buffer.add( pos++, e );
+                }
+                break;
             }
         }
+        buffer.forEach( this::pushEvent );
+   }
 
-        super.endElement( uri, localName, qName );
-        state = "";
-    }
 
-    protected Optional<RelativeProject> resolveRelativePath( Path relativePath )
+    protected Optional<RelativeProject> resolveRelativePath( Path relativePath, String groupId, String artifactId )
     {
         Path pomPath = projectPath.resolve( relativePath );
         if ( Files.isDirectory( pomPath ) )
@@ -222,4 +171,5 @@ class ParentXMLFilter
         }
         return Optional.empty();
     }
+
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilter.java
deleted file mode 100644
index 767cb0b..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilter.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-
-/**
- * XML Filter to transform pom.xml to consumer pom.
- * This often means stripping of build-specific information.
- * When extra information is required during filtering it is probably a member of the BuildPomXMLFilter
- *
- * This filter is used at one location:
- * - org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory when publishing POM files.
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class RawToConsumerPomXMLFilter extends AbstractSAXFilter
-{
-    RawToConsumerPomXMLFilter( AbstractSAXFilter filter )
-    {
-        super( filter );
-    }
-
-    /**
-     * Don't allow overwriting parent
-     */
-    @Override
-    public final void setParent( XMLReader parent )
-    {
-        if ( getParent() == null )
-        {
-            super.setParent( parent );
-        }
-    }
-
-    @Override
-    public LexicalHandler getLexicalHandler()
-    {
-        return ( (AbstractSAXFilter) getParent() ).getLexicalHandler();
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
index d03b9e8..aa0c432 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
@@ -21,11 +21,7 @@ package org.apache.maven.model.transform;
 
 import java.nio.file.Path;
 
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.xml.sax.SAXException;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  *
@@ -41,20 +37,19 @@ public class RawToConsumerPomXMLFilterFactory
         this.buildPomXMLFilterFactory = buildPomXMLFilterFactory;
     }
 
-    public final RawToConsumerPomXMLFilter get( Path projectPath )
-        throws SAXException, ParserConfigurationException, TransformerConfigurationException
+    public final XmlPullParser get( XmlPullParser parser, Path projectPath )
     {
-        BuildToRawPomXMLFilter parent = buildPomXMLFilterFactory.get( projectPath );
+        parser = buildPomXMLFilterFactory.get( parser, projectPath );
 
 
         // Ensure that xs:any elements aren't touched by next filters
-        AbstractSAXFilter filter = new FastForwardFilter( parent );
+        parser = new FastForwardFilter( parser );
 
         // Strip modules
-        filter = new ModulesXMLFilter( filter );
+        parser = new ModulesXMLFilter( parser );
         // Adjust relativePath
-        filter = new RelativePathXMLFilter( filter );
+        parser = new RelativePathXMLFilter( parser );
 
-        return new RawToConsumerPomXMLFilter( filter );
+        return parser;
     }
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
index b2d3ca4..7f9dd3b 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
@@ -19,153 +19,95 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
+import java.util.List;
 import java.util.function.BiFunction;
 
-import org.apache.maven.model.transform.sax.SAXEventUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
+import org.apache.maven.model.transform.pull.NodeBufferingParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  * Will apply the version if the dependency is part of the reactor
  *
  * @author Robert Scholte
+ * @author Guillaume Nodet
  * @since 4.0.0
  */
-public class ReactorDependencyXMLFilter extends AbstractEventXMLFilter
+public class ReactorDependencyXMLFilter extends NodeBufferingParser
 {
-    private boolean parsingDependency;
-
-    // states
-    private String state;
-
-    // whiteSpace after <dependency>, to be used to position <version>
-    private String dependencyWhitespace;
-
-    private boolean hasVersion;
-
-    private String groupId;
-
-    private String artifactId;
-
     private final BiFunction<String, String, String> reactorVersionMapper;
 
-    public ReactorDependencyXMLFilter( BiFunction<String, String, String> reactorVersionMapper )
+    public ReactorDependencyXMLFilter( XmlPullParser xmlPullParser,
+                                       BiFunction<String, String, String> reactorVersionMapper )
     {
+        super( xmlPullParser, "dependency" );
         this.reactorVersionMapper = reactorVersionMapper;
     }
 
-    @Override
-    public void startElement( String uri, String localName, String qName, Attributes atts )
-        throws SAXException
-    {
-        if ( !parsingDependency && "dependency".equals( localName ) )
-        {
-            parsingDependency = true;
-        }
-
-        if ( parsingDependency )
-        {
-            state = localName;
-
-            hasVersion |= "version".equals( localName );
-        }
-        super.startElement( uri, localName, qName, atts );
-    }
-
-    @Override
-    public void characters( char[] ch, int start, int length )
-        throws SAXException
+    protected void process( List<Event> buffer )
     {
-        if ( parsingDependency )
+        // whiteSpace after <dependency>, to be used to position <version>
+        String dependencyWhitespace = "";
+        boolean hasVersion = false;
+        String groupId = null;
+        String artifactId = null;
+        String tagName = null;
+        for ( int i = 0; i < buffer.size(); i++ )
         {
-            final String eventState = state;
-            String value = new String( ch, start, length );
-            switch ( eventState )
+            Event event = buffer.get( i );
+            if ( event.event == START_TAG )
             {
-                case "dependency":
-                    dependencyWhitespace = nullSafeAppend( dependencyWhitespace, value );
-                    break;
-                case "groupId":
-                    groupId = nullSafeAppend( groupId, value );
-                    break;
-                case "artifactId":
-                    artifactId = nullSafeAppend( artifactId, value );
-                    break;
-                default:
-                    break;
+                tagName = event.name;
+                hasVersion |= "version".equals( tagName );
             }
-        }
-        super.characters( ch, start, length );
-    }
-
-    @Override
-    public void endElement( String uri, final String localName, String qName )
-        throws SAXException
-    {
-        if ( parsingDependency )
-        {
-            switch ( localName )
+            else if ( event.event == TEXT )
             {
-                case "dependency":
-                    if ( !hasVersion )
+                if ( event.text.matches( "\\s+" ) )
+                {
+                    if ( dependencyWhitespace.isEmpty() )
                     {
-                        String version = getVersion();
-
-                        // dependency is not part of reactor, probably it is managed
-                        if ( version != null )
-                        {
-                            try ( Includer i = super.include() )
-                            {
-                                if ( dependencyWhitespace != null )
-                                {
-                                    super.characters( dependencyWhitespace.toCharArray(), 0,
-                                                      dependencyWhitespace.length() );
-
-                                }
-                                String versionQName = SAXEventUtils.renameQName( qName, "version" );
-
-                                super.startElement( uri, "version", versionQName, null );
-                                super.characters( version.toCharArray(), 0, version.length() );
-                                super.endElement( uri, "version", versionQName );
-                            }
-                        }
+                        dependencyWhitespace = event.text;
                     }
-                    super.executeEvents();
-
-                    parsingDependency = false;
-
-                    // reset
-                    hasVersion = false;
-                    dependencyWhitespace = null;
-                    groupId = null;
-                    artifactId = null;
-
-                    break;
-                default:
-                    break;
+                }
+                else if ( "groupId".equals( tagName ) )
+                {
+                    groupId = nullSafeAppend( groupId, event.text );
+                }
+                else if ( "artifactId".equals( tagName ) )
+                {
+                    artifactId = nullSafeAppend( artifactId, event.text );
+                }
+            }
+            else if ( event.event == END_TAG && "dependency".equals( event.name ) )
+            {
+                String version = reactorVersionMapper.apply( groupId, artifactId  );
+                if ( !hasVersion && version != null )
+                {
+                    int pos = buffer.get( i - 1 ).event == TEXT ? i - 1  : i;
+                    Event e = new Event();
+                    e.event = TEXT;
+                    e.text = dependencyWhitespace;
+                    buffer.add( pos++, e );
+                    e = new Event();
+                    e.event = START_TAG;
+                    e.namespace = buffer.get( 0 ).namespace;
+                    e.prefix = buffer.get( 0 ).prefix;
+                    e.name = "version";
+                    buffer.add( pos++, e );
+                    e = new Event();
+                    e.event = TEXT;
+                    e.text = version;
+                    buffer.add( pos++, e );
+                    e = new Event();
+                    e.event = END_TAG;
+                    e.name = "version";
+                    e.namespace = buffer.get( 0 ).namespace;
+                    e.prefix = buffer.get( 0 ).prefix;
+                    buffer.add( pos++, e );
+                }
+                break;
             }
         }
-
-        super.endElement( uri, localName, qName );
-
-        state = "";
-    }
-
-    private String getVersion()
-    {
-        return reactorVersionMapper.apply( groupId, artifactId  );
-    }
-
-    @Override
-    protected boolean isParsing()
-    {
-        return parsingDependency;
-    }
-
-    @Override
-    protected String getState()
-    {
-        return state;
+        buffer.forEach( this::pushEvent );
     }
 
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
index 2ca09ac..4368f2c 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
@@ -19,90 +19,60 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
+import java.util.List;
 
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
+import org.apache.maven.model.transform.pull.NodeBufferingParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
  * Remove relativePath element, has no value for consumer pom
  *
  * @author Robert Scholte
+ * @author Guillaume Nodet
  * @since 4.0.0
  */
-class RelativePathXMLFilter
-    extends AbstractEventXMLFilter
+public class RelativePathXMLFilter extends NodeBufferingParser
 {
-    private boolean parsingParent;
 
-    private String state;
-
-    RelativePathXMLFilter()
-    {
-        super();
-    }
-
-    RelativePathXMLFilter( AbstractSAXFilter parent )
+    public RelativePathXMLFilter( XmlPullParser xmlPullParser )
     {
-        super( parent );
+        super( xmlPullParser, "parent" );
     }
 
-    @Override
-    public void startElement( String uri, final String localName, String qName, Attributes atts )
-        throws SAXException
+    protected void process( List<Event> buffer )
     {
-        if ( !parsingParent && "parent".equals( localName ) )
+        boolean skip = false;
+        Event prev = null;
+        for ( Event event : buffer )
         {
-            parsingParent = true;
-        }
-
-        if ( parsingParent )
-        {
-            state = localName;
-        }
-
-        super.startElement( uri, localName, qName, atts );
-    }
-
-    @Override
-    public void endElement( String uri, String localName, String qName )
-        throws SAXException
-    {
-        if ( parsingParent )
-        {
-            switch ( localName )
+            if ( event.event == START_TAG && "relativePath".equals( event.name ) )
             {
-                case "parent":
-                    executeEvents();
-
-                    parsingParent = false;
-                    break;
-                default:
-                    break;
+                skip = true;
+                if ( prev != null && prev.event == TEXT && prev.text.matches( "\\s+" ) )
+                {
+                    prev = null;
+                }
+                event = null;
+            }
+            else if ( event.event == END_TAG && "relativePath".equals( event.name ) )
+            {
+                skip = false;
+                event = null;
+            }
+            else
+            {
+                if ( skip )
+                {
+                    event = null;
+                }
+            }
+            if ( prev != null )
+            {
+                pushEvent( prev );
             }
+            prev = event;
         }
-
-        super.endElement( uri, localName, qName );
-
-        // for this simple structure resetting to parent it sufficient
-        state = "parent";
+        pushEvent( prev );
     }
 
-    @Override
-    protected boolean isParsing()
-    {
-        return parsingParent;
-    }
-
-    @Override
-    protected String getState()
-    {
-        return state;
-    }
-
-    @Override
-    protected boolean acceptEvent( String state )
-    {
-        return !"relativePath".equals( state );
-    }
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/BufferingParser.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/BufferingParser.java
new file mode 100644
index 0000000..f8235d8
--- /dev/null
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/BufferingParser.java
@@ -0,0 +1,563 @@
+package org.apache.maven.model.transform.pull;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Objects;
+
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * An xml pull parser filter base implementation.
+ *
+ * @author Guillaume Nodet
+ * @since 4.0.0
+ */
+public class BufferingParser implements XmlPullParser
+{
+
+    protected XmlPullParser xmlPullParser;
+    protected Deque<Event> events;
+    protected Event current;
+    protected boolean disabled;
+
+    @SuppressWarnings( "checkstyle:VisibilityModifier" )
+    public static class Event
+    {
+        public int event;
+        public String name;
+        public String prefix;
+        public String namespace;
+        public boolean empty;
+        public String text;
+        public Attribute[] attributes;
+        public Namespace[] namespaces;
+    }
+
+    @SuppressWarnings( "checkstyle:VisibilityModifier" )
+    public static class Namespace
+    {
+        public String prefix;
+        public String uri;
+    }
+
+    @SuppressWarnings( "checkstyle:VisibilityModifier" )
+    public static class Attribute
+    {
+        public String name;
+        public String prefix;
+        public String namespace;
+        public String type;
+        public String value;
+        public boolean isDefault;
+    }
+
+
+    public BufferingParser( XmlPullParser xmlPullParser )
+    {
+        this.xmlPullParser = xmlPullParser;
+    }
+
+    @Override
+    public void setFeature( String name, boolean state ) throws XmlPullParserException
+    {
+        xmlPullParser.setFeature( name, state );
+    }
+
+    @Override
+    public boolean getFeature( String name )
+    {
+        return xmlPullParser.getFeature( name );
+    }
+
+    @Override
+    public void setProperty( String name, Object value ) throws XmlPullParserException
+    {
+        xmlPullParser.setProperty( name, value );
+    }
+
+    @Override
+    public Object getProperty( String name )
+    {
+        return xmlPullParser.getProperty( name );
+    }
+
+    @Override
+    public void setInput( Reader in ) throws XmlPullParserException
+    {
+        xmlPullParser.setInput( in );
+    }
+
+    @Override
+    public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
+    {
+        xmlPullParser.setInput( inputStream, inputEncoding );
+    }
+
+    @Override
+    public String getInputEncoding()
+    {
+        return xmlPullParser.getInputEncoding();
+    }
+
+    @Override
+    public void defineEntityReplacementText( String entityName, String replacementText ) throws XmlPullParserException
+    {
+        xmlPullParser.defineEntityReplacementText( entityName, replacementText );
+    }
+
+    @Override
+    public int getNamespaceCount( int depth ) throws XmlPullParserException
+    {
+//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
+        return xmlPullParser.getNamespaceCount( depth );
+    }
+
+    @Override
+    public String getNamespacePrefix( int pos ) throws XmlPullParserException
+    {
+//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
+        return xmlPullParser.getNamespacePrefix( pos );
+    }
+
+    @Override
+    public String getNamespaceUri( int pos ) throws XmlPullParserException
+    {
+//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
+        return xmlPullParser.getNamespaceUri( pos );
+    }
+
+    @Override
+    public String getNamespace( String prefix )
+    {
+//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
+        return xmlPullParser.getNamespace( prefix );
+    }
+
+    @Override
+    public int getDepth()
+    {
+//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
+        return xmlPullParser.getDepth();
+    }
+
+    @Override
+    public String getPositionDescription()
+    {
+        if ( current != null )
+        {
+            throw new IllegalStateException( "Not supported during events replay" );
+        }
+        return xmlPullParser.getPositionDescription();
+    }
+
+    @Override
+    public int getLineNumber()
+    {
+        if ( current != null )
+        {
+            throw new IllegalStateException( "Not supported during events replay" );
+        }
+        return xmlPullParser.getLineNumber();
+    }
+
+    @Override
+    public int getColumnNumber()
+    {
+        if ( current != null )
+        {
+            throw new IllegalStateException( "Not supported during events replay" );
+        }
+        return xmlPullParser.getColumnNumber();
+    }
+
+    @Override
+    public boolean isWhitespace() throws XmlPullParserException
+    {
+        if ( current != null )
+        {
+            if ( current.event == TEXT || current.event == CDSECT )
+            {
+                return current.text.matches( "[ \r\t\n]+" );
+            }
+            else if ( current.event == IGNORABLE_WHITESPACE )
+            {
+                return true;
+            }
+            else
+            {
+                throw new XmlPullParserException( "no content available to check for whitespaces" );
+            }
+        }
+        return xmlPullParser.isWhitespace();
+    }
+
+    @Override
+    public String getText()
+    {
+        return current != null ? current.text : xmlPullParser.getText();
+    }
+
+    @Override
+    public char[] getTextCharacters( int[] holderForStartAndLength )
+    {
+        if ( current != null )
+        {
+            throw new IllegalStateException( "Not supported during events replay" );
+        }
+        return xmlPullParser.getTextCharacters( holderForStartAndLength );
+    }
+
+    @Override
+    public String getNamespace()
+    {
+        return current != null ? current.namespace : xmlPullParser.getNamespace();
+    }
+
+    @Override
+    public String getName()
+    {
+        return current != null ? current.name : xmlPullParser.getName();
+    }
+
+    @Override
+    public String getPrefix()
+    {
+        return current != null ? current.prefix : xmlPullParser.getPrefix();
+    }
+
+    @Override
+    public boolean isEmptyElementTag() throws XmlPullParserException
+    {
+        return current != null ? current.empty : xmlPullParser.isEmptyElementTag();
+    }
+
+    @Override
+    public int getAttributeCount()
+    {
+        if ( current != null )
+        {
+            return current.attributes != null ? current.attributes.length : 0;
+        }
+        else
+        {
+            return xmlPullParser.getAttributeCount();
+        }
+    }
+
+    @Override
+    public String getAttributeNamespace( int index )
+    {
+        if ( current != null )
+        {
+            return current.attributes[index].namespace;
+        }
+        else
+        {
+            return xmlPullParser.getAttributeNamespace( index );
+        }
+    }
+
+    @Override
+    public String getAttributeName( int index )
+    {
+        if ( current != null )
+        {
+            return current.attributes[index].name;
+        }
+        else
+        {
+            return xmlPullParser.getAttributeName( index );
+        }
+    }
+
+    @Override
+    public String getAttributePrefix( int index )
+    {
+        if ( current != null )
+        {
+            return current.attributes[index].prefix;
+        }
+        else
+        {
+            return xmlPullParser.getAttributePrefix( index );
+        }
+    }
+
+    @Override
+    public String getAttributeType( int index )
+    {
+        if ( current != null )
+        {
+            return current.attributes[index].type;
+        }
+        else
+        {
+            return xmlPullParser.getAttributeType( index );
+        }
+    }
+
+    @Override
+    public boolean isAttributeDefault( int index )
+    {
+        if ( current != null )
+        {
+            return current.attributes[index].isDefault;
+        }
+        else
+        {
+            return xmlPullParser.isAttributeDefault( index );
+        }
+    }
+
+    @Override
+    public String getAttributeValue( int index )
+    {
+        if ( current != null )
+        {
+            return current.attributes[index].value;
+        }
+        else
+        {
+            return xmlPullParser.getAttributeValue( index );
+        }
+    }
+
+    @Override
+    public String getAttributeValue( String namespace, String name )
+    {
+        if ( current != null )
+        {
+            if ( current.attributes != null )
+            {
+                for ( Attribute attr : current.attributes )
+                {
+                    if ( Objects.equals( namespace, attr.namespace )
+                            && Objects.equals( name, attr.name ) )
+                    {
+                        return attr.value;
+                    }
+                }
+            }
+            return null;
+        }
+        else
+        {
+            return xmlPullParser.getAttributeValue( namespace, name );
+        }
+    }
+
+    @Override
+    public void require( int type, String namespace, String name ) throws XmlPullParserException, IOException
+    {
+        if ( current != null )
+        {
+            throw new IllegalStateException( "Not supported during events replay" );
+        }
+        xmlPullParser.require( type, namespace, name );
+    }
+
+    @Override
+    public int getEventType() throws XmlPullParserException
+    {
+        return current != null ? current.event : xmlPullParser.getEventType();
+    }
+
+    @Override
+    public int next() throws XmlPullParserException, IOException
+    {
+        while ( true )
+        {
+            if ( events != null && !events.isEmpty() )
+            {
+                current = events.removeFirst();
+                return current.event;
+            }
+            else
+            {
+                current = null;
+            }
+            if ( getEventType() == END_DOCUMENT )
+            {
+                throw new XmlPullParserException( "already reached end of XML input", this, null );
+            }
+            int currentEvent = xmlPullParser.next();
+            if ( disabled || accept() )
+            {
+                return currentEvent;
+            }
+        }
+    }
+
+    @Override
+    public int nextToken() throws XmlPullParserException, IOException
+    {
+        while ( true )
+        {
+            if ( events != null && !events.isEmpty() )
+            {
+                current = events.removeFirst();
+                return current.event;
+            }
+            else
+            {
+                current = null;
+            }
+            if ( getEventType() == END_DOCUMENT )
+            {
+                throw new XmlPullParserException( "already reached end of XML input", this, null );
+            }
+            int currentEvent = xmlPullParser.nextToken();
+            if ( accept() )
+            {
+                return currentEvent;
+            }
+        }
+    }
+
+    @Override
+    public int nextTag() throws XmlPullParserException, IOException
+    {
+        int eventType = next();
+        if ( eventType == TEXT && isWhitespace() )
+        { // skip whitespace
+            eventType = next();
+        }
+        if ( eventType != START_TAG && eventType != END_TAG )
+        {
+            throw new XmlPullParserException( "expected START_TAG or END_TAG not "
+                    + TYPES[getEventType()], this, null );
+        }
+        return eventType;
+    }
+
+    @Override
+    public String nextText() throws XmlPullParserException, IOException
+    {
+        int eventType = getEventType();
+        if ( eventType != START_TAG )
+        {
+            throw new XmlPullParserException( "parser must be on START_TAG to read next text", this, null );
+        }
+        eventType = next();
+        if ( eventType == TEXT )
+        {
+            final String result = getText();
+            eventType = next();
+            if ( eventType != END_TAG )
+            {
+                throw new XmlPullParserException( "TEXT must be immediately followed by END_TAG and not "
+                        + TYPES[getEventType()], this, null );
+            }
+            return result;
+        }
+        else if ( eventType == END_TAG )
+        {
+            return "";
+        }
+        else
+        {
+            throw new XmlPullParserException( "parser must be on START_TAG or TEXT to read text", this, null );
+        }
+    }
+
+    protected Event bufferEvent() throws XmlPullParserException
+    {
+        Event event = new Event();
+        XmlPullParser pp = xmlPullParser;
+        event.event = xmlPullParser.getEventType();
+        switch ( event.event )
+        {
+            case START_DOCUMENT:
+            case END_DOCUMENT:
+                break;
+            case START_TAG:
+                event.name = pp.getName();
+                event.namespace = pp.getNamespace();
+                event.prefix = pp.getPrefix();
+                event.empty = pp.isEmptyElementTag();
+                event.text = pp.getText();
+                break;
+            case END_TAG:
+                event.name = pp.getName();
+                event.namespace = pp.getNamespace();
+                event.prefix = pp.getPrefix();
+                event.text = pp.getText();
+                break;
+            case TEXT:
+            case COMMENT:
+            case IGNORABLE_WHITESPACE:
+                event.text = pp.getText();
+                break;
+            default:
+                break;
+        }
+        return event;
+    }
+
+    protected void pushEvent( Event event )
+    {
+        if ( events == null )
+        {
+            events = new ArrayDeque<>();
+        }
+        events.add( event );
+    }
+
+    protected boolean accept() throws XmlPullParserException, IOException
+    {
+        return true;
+    }
+
+    protected void enable()
+    {
+        disabled = false;
+    }
+
+    protected void disable()
+    {
+        if ( events != null && !events.isEmpty() )
+        {
+            throw new IllegalStateException( "Can not disable filter while processing" );
+        }
+        disabled = true;
+        if ( xmlPullParser instanceof BufferingParser )
+        {
+            ( ( BufferingParser ) xmlPullParser ).disable();
+        }
+    }
+
+    protected static String nullSafeAppend( String originalValue, String charSegment )
+    {
+        if ( originalValue == null )
+        {
+            return charSegment;
+        }
+        else
+        {
+            return originalValue + charSegment;
+        }
+    }
+}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/NodeBufferingParser.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/NodeBufferingParser.java
new file mode 100644
index 0000000..7ea1e3e
--- /dev/null
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/NodeBufferingParser.java
@@ -0,0 +1,81 @@
+package org.apache.maven.model.transform.pull;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Buffer events while parsing a given element to allow some post-processing.
+ *
+ * @author Guillaume Nodet
+ * @since 4.0.0
+ */
+public abstract class NodeBufferingParser extends BufferingParser
+{
+
+    private final List<Event> buffer = new ArrayList<>();
+
+    private final String nodeName;
+
+    private boolean buffering;
+
+    public NodeBufferingParser( XmlPullParser xmlPullParser, String nodeName )
+    {
+        super( xmlPullParser );
+        this.nodeName = Objects.requireNonNull( nodeName );
+    }
+
+    @Override
+    protected boolean accept() throws XmlPullParserException, IOException
+    {
+        if ( nodeName.equals( xmlPullParser.getName() ) )
+        {
+            if ( xmlPullParser.getEventType() == START_TAG && !buffering )
+            {
+                buffer.add( bufferEvent() );
+                buffering = true;
+                return false;
+            }
+            if ( xmlPullParser.getEventType() == END_TAG && buffering )
+            {
+                buffer.add( bufferEvent() );
+                process( buffer );
+                buffering = false;
+                buffer.clear();
+                return false;
+            }
+        }
+        else if ( buffering )
+        {
+            buffer.add( bufferEvent() );
+            return false;
+        }
+        return true;
+    }
+
+    protected abstract void process( List<Event> buffer );
+
+}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java
new file mode 100644
index 0000000..c583a18
--- /dev/null
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java
@@ -0,0 +1,132 @@
+package org.apache.maven.model.transform.pull;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import org.codehaus.plexus.util.xml.XmlStreamReader;
+import org.codehaus.plexus.util.xml.pull.MXSerializer;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.codehaus.plexus.util.xml.pull.XmlSerializer;
+
+public class XmlUtils
+{
+
+    public static ByteArrayInputStream writeDocument( XmlStreamReader reader, XmlPullParser parser )
+            throws IOException, XmlPullParserException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Writer writer = newWriter( reader, baos );
+        writeDocument( parser, writer );
+        return new ByteArrayInputStream( baos.toByteArray() );
+    }
+
+    public static void writeDocument( XmlPullParser parser, Writer writer )
+            throws IOException, XmlPullParserException
+    {
+        XmlSerializer serializer = new MXSerializer();
+        serializer.setOutput( writer );
+
+        while ( parser.nextToken() != XmlPullParser.END_DOCUMENT )
+        {
+            switch ( parser.getEventType() )
+            {
+                case XmlPullParser.START_DOCUMENT:
+                    serializer.startDocument( parser.getInputEncoding(), true );
+                    break;
+                case XmlPullParser.END_DOCUMENT:
+                    serializer.endDocument();
+                case XmlPullParser.START_TAG:
+                    int nsStart = parser.getNamespaceCount( parser.getDepth() - 1 );
+                    int nsEnd = parser.getNamespaceCount( parser.getDepth() );
+                    for ( int i = nsStart; i < nsEnd; i++ )
+                    {
+                        String prefix = parser.getNamespacePrefix( i );
+                        String ns = parser.getNamespaceUri( i );
+                        serializer.setPrefix( prefix, ns );
+                    }
+                    serializer.startTag( parser.getNamespace(), parser.getName() );
+                    for ( int i = 0; i < parser.getAttributeCount(); i++ )
+                    {
+                        serializer.attribute( parser.getAttributeNamespace( i ),
+                                              parser.getAttributeName( i ),
+                                              parser.getAttributeValue( i ) );
+                    }
+                    break;
+                case XmlPullParser.END_TAG:
+                    serializer.endTag( parser.getNamespace(), parser.getName() );
+                    break;
+                case XmlPullParser.TEXT:
+                    serializer.text( normalize( parser.getText() ) );
+                    break;
+                case XmlPullParser.CDSECT:
+                    serializer.cdsect( parser.getText() );
+                    break;
+                case XmlPullParser.ENTITY_REF:
+                    serializer.entityRef( parser.getText() );
+                    break;
+                case XmlPullParser.IGNORABLE_WHITESPACE:
+                    serializer.ignorableWhitespace( normalize( parser.getText() ) );
+                    break;
+                case XmlPullParser.PROCESSING_INSTRUCTION:
+                    serializer.processingInstruction( parser.getText() );
+                    break;
+                case XmlPullParser.COMMENT:
+                    serializer.comment( normalize( parser.getText() ) );
+                    break;
+                case XmlPullParser.DOCDECL:
+                    serializer.docdecl( normalize( parser.getText() ) );
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        serializer.endDocument();
+    }
+
+    private static OutputStreamWriter newWriter( XmlStreamReader reader, ByteArrayOutputStream baos )
+            throws UnsupportedEncodingException
+    {
+        if ( reader.getEncoding() != null )
+        {
+            return new OutputStreamWriter( baos, reader.getEncoding() );
+        }
+        else
+        {
+            return new OutputStreamWriter( baos );
+        }
+    }
+
+    private static String normalize( String input )
+    {
+        if ( input.indexOf( '\n' ) >= 0 && !"\n".equals( System.lineSeparator() ) )
+        {
+            return input.replace( "\n", System.lineSeparator() );
+        }
+        return input;
+    }
+}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/AbstractSAXFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/AbstractSAXFilter.java
deleted file mode 100644
index 7189910..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/AbstractSAXFilter.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
-import org.xml.sax.helpers.XMLFilterImpl;
-
-/**
- * XMLFilter with LexicalHandler.
- * Since some filters collect events before processing them, the LexicalHandler events must be collected too.
- * Otherwise the LexicalHandler events might end up before all collected XMLReader events.
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class AbstractSAXFilter extends XMLFilterImpl implements LexicalHandler
-{
-    private LexicalHandler lexicalHandler;
-
-    public AbstractSAXFilter()
-    {
-        super();
-    }
-
-    public AbstractSAXFilter( AbstractSAXFilter parent )
-    {
-        super( parent );
-        parent.setLexicalHandler( this );
-    }
-
-    public LexicalHandler getLexicalHandler()
-    {
-        return lexicalHandler;
-    }
-
-    public void setLexicalHandler( LexicalHandler lexicalHandler )
-    {
-        this.lexicalHandler = lexicalHandler;
-    }
-
-    @Override
-    public void startDTD( String name, String publicId, String systemId )
-        throws SAXException
-    {
-        if ( lexicalHandler != null )
-        {
-            lexicalHandler.startDTD( name, publicId, systemId );
-        }
-    }
-
-    @Override
-    public void endDTD()
-        throws SAXException
-    {
-        if ( lexicalHandler != null )
-        {
-            lexicalHandler.endDTD();
-        }
-    }
-
-    @Override
-    public void startEntity( String name )
-        throws SAXException
-    {
-        if ( lexicalHandler != null )
-        {
-            lexicalHandler.startEntity( name );
-        }
-    }
-
-    @Override
-    public void endEntity( String name )
-        throws SAXException
-    {
-        if ( lexicalHandler != null )
-        {
-            lexicalHandler.endEntity( name );
-        }
-    }
-
-    @Override
-    public void startCDATA()
-        throws SAXException
-    {
-        if ( lexicalHandler != null )
-        {
-            lexicalHandler.startCDATA();
-        }
-    }
-
-    @Override
-    public void endCDATA()
-        throws SAXException
-    {
-        if ( lexicalHandler != null )
-        {
-            lexicalHandler.endCDATA();
-        }
-    }
-
-    @Override
-    public void comment( char[] ch, int start, int length )
-        throws SAXException
-    {
-        if ( lexicalHandler != null )
-        {
-            lexicalHandler.comment( ch, start, length );
-        }
-    }
-
-
-    protected static String nullSafeAppend( String originalValue, String charSegment )
-    {
-        if ( originalValue == null )
-        {
-            return charSegment;
-        }
-        else
-        {
-            return originalValue + charSegment;
-        }
-    }
-
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/CommentRenormalizer.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/CommentRenormalizer.java
deleted file mode 100644
index 6483731..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/CommentRenormalizer.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
-
-/**
- * During parsing the line separators are transformed to \n
- * Unlike characters(), comments don't use the systems line separator for serialization.
- * Hence use this class in the LexicalHandler chain to do so
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class CommentRenormalizer implements LexicalHandler
-{
-    private final LexicalHandler lexicalHandler;
-
-    private final String lineSeparator;
-
-    public CommentRenormalizer( LexicalHandler lexicalHandler )
-    {
-        this( lexicalHandler,  System.lineSeparator() );
-    }
-
-    // for testing purpose
-    CommentRenormalizer( LexicalHandler lexicalHandler, String lineSeparator )
-    {
-        this.lexicalHandler = lexicalHandler;
-        this.lineSeparator = lineSeparator;
-    }
-
-    @Override
-    public void comment( char[] ch, int start, int length )
-        throws SAXException
-    {
-        if ( "\n".equals( lineSeparator ) )
-        {
-            lexicalHandler.comment( ch, start, length );
-        }
-        else
-        {
-            char[] ca = new String( ch, start, length ).replaceAll( "\n", lineSeparator ).toCharArray();
-
-            lexicalHandler.comment( ca, 0, ca.length );
-        }
-    }
-
-    @Override
-    public void startDTD( String name, String publicId, String systemId )
-        throws SAXException
-    {
-        lexicalHandler.startDTD( name, publicId, systemId );
-    }
-
-    @Override
-    public void endDTD()
-        throws SAXException
-    {
-        lexicalHandler.endDTD();
-    }
-
-    @Override
-    public void startEntity( String name )
-        throws SAXException
-    {
-        lexicalHandler.startEntity( name );
-    }
-
-    @Override
-    public void endEntity( String name )
-        throws SAXException
-    {
-        lexicalHandler.endEntity( name );
-    }
-
-    @Override
-    public void startCDATA()
-        throws SAXException
-    {
-        lexicalHandler.startCDATA();
-    }
-
-    @Override
-    public void endCDATA()
-        throws SAXException
-    {
-        lexicalHandler.endCDATA();
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/Factories.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/Factories.java
deleted file mode 100644
index 835ab0d..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/Factories.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.xml.XMLConstants;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerFactory;
-
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXNotRecognizedException;
-import org.xml.sax.SAXNotSupportedException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-/**
- * Creates XML related factories with OWASP advices applied
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public final class Factories
-{
-    private Factories()
-    {
-    }
-
-    /**
-     * See
-     * https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#transformerfactory
-     */
-    public static TransformerFactory newTransformerFactory()
-    {
-        TransformerFactory tf = TransformerFactory.newInstance();
-        tf.setAttribute( XMLConstants.ACCESS_EXTERNAL_DTD, "" );
-        tf.setAttribute( XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "" );
-
-        return tf;
-    }
-
-    public static XMLReader newXMLReader() throws SAXException, ParserConfigurationException
-    {
-        XMLReader reader = XMLReaderFactory.createXMLReader();
-
-        try
-        {
-            // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
-            // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
-
-            // Using the XMLReader's setFeature
-            reader.setFeature( "http://xml.org/sax/features/external-general-entities", false );
-        }
-        catch ( SAXNotRecognizedException e )
-        {
-            // Tried an unknown feature.
-        }
-        catch ( SAXNotSupportedException e )
-        {
-            // Tried a feature known to the parser but unsupported.
-        }
-        return reader;
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEvent.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEvent.java
deleted file mode 100644
index fae783b..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEvent.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.xml.sax.SAXException;
-
-/**
- * Command pattern to gather events which can be executed later on.
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-@FunctionalInterface
-public interface SAXEvent
-{
-    void execute() throws SAXException;
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEventFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEventFactory.java
deleted file mode 100644
index 8625762..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEventFactory.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.Locator;
-import org.xml.sax.ext.LexicalHandler;
-
-/**
- * Factory for SAXEvents
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public final class SAXEventFactory
-{
-    private final ContentHandler contentHandler;
-
-    private final LexicalHandler lexicalHandler;
-
-    protected SAXEventFactory( ContentHandler contentHandler, LexicalHandler lexicalHandler )
-    {
-        this.contentHandler = contentHandler;
-        this.lexicalHandler = lexicalHandler;
-    }
-
-    public SAXEvent characters( final char[] ch, final int start, final int length )
-    {
-        final char[] txt = new char[length];
-        System.arraycopy( ch, start, txt, 0, length );
-        return () -> contentHandler.characters( txt, 0, length );
-    }
-
-    public SAXEvent endDocument()
-    {
-        return () -> contentHandler.endDocument();
-    }
-
-    public SAXEvent endElement( final String uri, final String localName, final String qName )
-    {
-        return () -> contentHandler.endElement( uri, localName, qName );
-    }
-
-    public SAXEvent endPrefixMapping( final String prefix )
-    {
-        return () ->  contentHandler.endPrefixMapping( prefix );
-    }
-
-    public SAXEvent ignorableWhitespace( final char[] ch, final int start, final int length )
-    {
-        return () ->  contentHandler.ignorableWhitespace( ch, start, length );
-    }
-
-    public SAXEvent processingInstruction( final String target, final String data )
-    {
-        return () -> contentHandler.processingInstruction( target, data );
-    }
-
-    public SAXEvent setDocumentLocator( final Locator locator )
-    {
-        return () -> contentHandler.setDocumentLocator( locator );
-    }
-
-    public SAXEvent skippedEntity( final String name )
-    {
-        return () -> contentHandler.skippedEntity( name );
-    }
-
-    public SAXEvent startDocument()
-    {
-        return () -> contentHandler.startDocument();
-    }
-
-    public SAXEvent startElement( final String uri, final String localName, final String qName, final Attributes atts )
-    {
-        return () -> contentHandler.startElement( uri, localName, qName, atts );
-    }
-
-    public SAXEvent startPrefixMapping( final String prefix, final String uri )
-    {
-        return () -> contentHandler.startPrefixMapping( prefix, uri );
-    }
-
-    public static SAXEventFactory newInstance( ContentHandler contentHandler, LexicalHandler lexicalHandler )
-    {
-        return new SAXEventFactory( contentHandler, lexicalHandler );
-    }
-
-    public SAXEvent startDTD( String name, String publicId, String systemId )
-    {
-        return () -> lexicalHandler.startDTD( name, publicId, systemId );
-    }
-
-    public SAXEvent endDTD()
-    {
-        return () -> lexicalHandler.endDTD();
-    }
-
-    public SAXEvent startEntity( String name )
-    {
-        return () -> lexicalHandler.startEntity( name );
-    }
-
-    public SAXEvent endEntity( String name )
-    {
-        return () -> lexicalHandler.endEntity( name );
-
-    }
-
-    public SAXEvent startCDATA()
-    {
-        return () -> lexicalHandler.startCDATA();
-    }
-
-    public SAXEvent endCDATA()
-    {
-        return () -> lexicalHandler.endCDATA();
-    }
-
-    public SAXEvent comment( char[] ch, int start, int length )
-    {
-        final char[] txt = new char[length];
-        System.arraycopy( ch, start, txt, 0, length );
-        return () -> lexicalHandler.comment(  txt, 0, length );
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEventUtils.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEventUtils.java
deleted file mode 100644
index b718d97..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/sax/SAXEventUtils.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.regex.Pattern;
-
-/**
- * Utility class for SAXEvents
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public final class SAXEventUtils
-{
-    private static final Pattern PATTERN = Pattern.compile( "[^:]+$" );
-
-    private SAXEventUtils()
-    {
-    }
-
-    /**
-     * Returns the newLocalName prefixed with the namespace of the oldQName if present
-     *
-     * @param oldQName the QName, used for its namespace
-     * @param newLocalName the preferred localName
-     * @return the new QName
-     */
-    public static String renameQName( String oldQName, String newLocalName )
-    {
-        return PATTERN.matcher( oldQName ).replaceFirst( newLocalName );
-    }
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/AbstractXMLFilterTests.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/AbstractXMLFilterTests.java
index 300d6a1..a18f81a 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/AbstractXMLFilterTests.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/AbstractXMLFilterTests.java
@@ -19,191 +19,41 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
+import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
 import java.io.StringWriter;
-import java.io.Writer;
-import java.net.ContentHandler;
-import java.util.function.Consumer;
 
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamResult;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.apache.maven.model.transform.sax.Factories;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
+import org.apache.maven.model.transform.pull.XmlUtils;
+import org.codehaus.plexus.util.xml.pull.MXParser;
+import org.codehaus.plexus.util.xml.pull.MXSerializer;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 public abstract class AbstractXMLFilterTests
 {
-    protected AbstractSAXFilter getFilter() throws TransformerException, SAXException, ParserConfigurationException
+    protected XmlPullParser getFilter(XmlPullParser parser)
     {
         throw new UnsupportedOperationException( "Override one of the getFilter() methods" );
     }
 
-    protected AbstractSAXFilter getFilter( Consumer<LexicalHandler> result )  throws TransformerException, SAXException, ParserConfigurationException
-    {
-        return getFilter();
-    }
-
-    protected String omitXmlDeclaration()
-    {
-        return "yes";
-    }
-
-    protected String indentAmount()
-    {
-        return null;
-    }
-
     protected String transform( String input )
-        throws TransformerException, SAXException, ParserConfigurationException
+        throws XmlPullParserException, IOException
     {
         return transform( new StringReader( input ) );
     }
 
-    /**
-     * Use this method only for testing a single filter.
-     *
-     * @param input
-     * @param filter
-     * @return
-     * @throws TransformerException
-     * @throws SAXException
-     * @throws ParserConfigurationException
-     */
-    protected String transform( String input, AbstractSAXFilter filter )
-        throws TransformerException, SAXException, ParserConfigurationException
-    {
-        setParent( filter );
-
-        SAXTransformerFactory transformerFactory = (SAXTransformerFactory) Factories.newTransformerFactory();
-        TransformerHandler transformerHandler = transformerFactory.newTransformerHandler();
-
-        transformerHandler.getTransformer().setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, omitXmlDeclaration() );
-        if ( indentAmount() != null )
-        {
-            transformerHandler.getTransformer().setOutputProperty( OutputKeys.INDENT, "yes" );
-            transformerHandler.getTransformer().setOutputProperty( "{http://xml.apache.org/xslt}indent-amount",
-                                                                   indentAmount() );
-        }
-
-        Transformer transformer = transformerFactory.newTransformer();
-
-        Writer writer = new StringWriter();
-        StreamResult result = new StreamResult( writer );
-        transformerHandler.setResult( result );
-
-        SAXResult transformResult = new SAXResult( transformerHandler );
-        SAXSource transformSource = new SAXSource( filter, new InputSource( new StringReader( input ) ) );
-
-        transformResult.setLexicalHandler( filter );
-        transformer.transform( transformSource, transformResult );
-
-        return writer.toString();
-
-    }
-
     protected String transform( Reader input )
-        throws TransformerException, SAXException, ParserConfigurationException
-    {
-        SAXTransformerFactory transformerFactory = (SAXTransformerFactory) Factories.newTransformerFactory();
-        TransformerHandler transformerHandler = transformerFactory.newTransformerHandler();
-
-        transformerHandler.getTransformer().setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, omitXmlDeclaration() );
-        if ( indentAmount() != null )
-        {
-            transformerHandler.getTransformer().setOutputProperty( OutputKeys.INDENT, "yes" );
-            transformerHandler.getTransformer().setOutputProperty( "{http://xml.apache.org/xslt}indent-amount",
-                                                                   indentAmount() );
-        }
-
-        Transformer transformer = transformerFactory.newTransformer();
-
-        Writer writer = new StringWriter();
-        StreamResult result = new StreamResult( writer );
-        transformerHandler.setResult( result );
-
-        SAXResult transformResult = new SAXResult( transformerHandler );
-
-        AbstractSAXFilter filter = getFilter( l -> transformResult.setLexicalHandler( l ) );
-        setParent( filter );
-
-        filter = new PerCharXMLFilter( filter );
-
-        filter.setLexicalHandler( transformerHandler );
-
-        SAXSource transformSource = new SAXSource( filter, new InputSource( input ) );
+            throws XmlPullParserException, IOException {
 
-        transformer.transform( transformSource, transformResult );
+        MXParser parser = new MXParser();
+        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+        parser.setInput(input);
+        XmlPullParser filter = getFilter( parser );
 
+        StringWriter writer = new StringWriter();
+        XmlUtils.writeDocument( filter, writer );
         return writer.toString();
     }
 
-    private void setParent( AbstractSAXFilter filter )
-        throws SAXException, ParserConfigurationException
-    {
-        if ( filter.getParent() == null )
-        {
-            XMLReader r = Factories.newXMLReader();
-
-            AbstractSAXFilter perChar = new PerCharXMLFilter();
-            perChar.setParent( r );
-
-            filter.setParent( perChar );
-            filter.setFeature( "http://xml.org/sax/features/namespaces", true );
-        }
-    }
-
-    /**
-     * From {@link ContentHandler}
-     * <q>Your code should not assume that algorithms using char-at-a-time idioms will be working in characterunits;
-     * in some cases they will split characters. This is relevant wherever XML permits arbitrary characters, such as
-     * attribute values,processing instruction data, and comments as well as in data reported from this method. It's
-     * also generally relevant whenever Java code manipulates internationalized text; the issue isn't unique to XML.</q>
-     *
-     * @author Robert Scholte
-     */
-    class PerCharXMLFilter
-        extends AbstractSAXFilter
-    {
-        public PerCharXMLFilter()
-        {
-            super();
-        }
-
-        public PerCharXMLFilter( AbstractSAXFilter parent )
-        {
-            super( parent );
-        }
-
-        @Override
-        public void characters( char[] ch, int start, int length )
-            throws SAXException
-        {
-            for ( int i = 0; i < length; i++ )
-            {
-                super.characters( ch, start + i, 1 );
-            }
-        }
-
-        @Override
-        public void ignorableWhitespace( char[] ch, int start, int length )
-            throws SAXException
-        {
-            for ( int i = 0; i < length; i++ )
-            {
-                super.ignorableWhitespace( ch, start + i, 1 );
-            }
-        }
-    }
 }
\ No newline at end of file
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/CiFriendlyXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/CiFriendlyXMLFilterTest.java
index 80cf84d..bfbbc11 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/CiFriendlyXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/CiFriendlyXMLFilterTest.java
@@ -19,32 +19,18 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerException;
-
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 import org.junit.jupiter.api.Test;
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
-import org.junit.jupiter.api.BeforeEach;
 
-import org.xml.sax.SAXException;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class CiFriendlyXMLFilterTest extends AbstractXMLFilterTests
 {
-    private CiFriendlyXMLFilter filter;
+    @Override
+    protected CiFriendlyXMLFilter getFilter(XmlPullParser parser) {
 
-    @BeforeEach
-    public void setUp()
-    {
-        filter = new CiFriendlyXMLFilter( true );
+        CiFriendlyXMLFilter filter = new CiFriendlyXMLFilter( parser, true );
         filter.setChangelist( "CHANGELIST" );
-    }
-
-    @Override
-    protected AbstractSAXFilter getFilter()
-        throws TransformerException, SAXException, ParserConfigurationException
-    {
         return filter;
     }
 
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
index 4fe2c19..3ecf255 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
@@ -25,30 +25,17 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Optional;
 import java.util.function.BiFunction;
-import java.util.function.Consumer;
 import java.util.function.Function;
 
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-
-import org.apache.maven.model.transform.sax.AbstractSAXFilter;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 import org.junit.jupiter.api.Test;
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
 
 public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
 {
     @Override
-    protected String omitXmlDeclaration()
-    {
-        return "no";
-    }
-
-    @Override
-    protected AbstractSAXFilter getFilter( Consumer<LexicalHandler> lexicalHandlerConsumer )
-        throws SAXException, ParserConfigurationException, TransformerConfigurationException
+    protected XmlPullParser getFilter( XmlPullParser parser )
     {
-        final BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory = new BuildToRawPomXMLFilterFactory( lexicalHandlerConsumer, true )
+        final BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory = new BuildToRawPomXMLFilterFactory( true )
         {
             @Override
             protected Function<Path, Optional<RelativeProject>> getRelativePathMapper()
@@ -82,10 +69,9 @@ public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
 
         };
 
-        RawToConsumerPomXMLFilter filter =
-            new RawToConsumerPomXMLFilterFactory( buildPomXMLFilterFactory ).get( Paths.get( "pom.xml" ) );
-        filter.setFeature( "http://xml.org/sax/features/namespaces", true );
-        return filter;
+        parser = new RawToConsumerPomXMLFilterFactory( buildPomXMLFilterFactory )
+                        .get( parser, Paths.get( "pom.xml" ) );
+        return parser;
     }
 
     @Test
@@ -254,8 +240,7 @@ public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
                         + "<!--post-in-->"
                         + "</modules>"
                         + "<!--after--></project>";
-        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
-                        "<project><!--before--><!--after--></project>";
+        String expected = "<project><!--before--><!--after--></project>";
         String actual = transform( input );
         assertThat( actual ).and( expected ).areIdentical();
     }
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
index ce4c8b2..b3b31f5 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
@@ -19,23 +19,19 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
-import java.util.function.Consumer;
-
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 import org.junit.jupiter.api.Test;
-import org.xml.sax.ext.LexicalHandler;
+
+import static org.xmlunit.assertj.XmlAssert.assertThat;
 
 public class ModulesXMLFilterTest
     extends AbstractXMLFilterTests
 {
 
     @Override
-    protected ModulesXMLFilter getFilter( Consumer<LexicalHandler> lexicalHandlerConsumer )
+    protected ModulesXMLFilter getFilter(XmlPullParser parser)
     {
-        ModulesXMLFilter filter = new ModulesXMLFilter();
-        lexicalHandlerConsumer.accept( filter );
-        return filter;
+        return new ModulesXMLFilter( parser );
     }
 
     @Test
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ParentXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ParentXMLFilterTest.java
index ac499fe..5c66e2f 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ParentXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ParentXMLFilterTest.java
@@ -19,32 +19,43 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Optional;
-import java.util.function.Consumer;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerException;
+import java.util.function.Function;
 
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class ParentXMLFilterTest
     extends AbstractXMLFilterTests
 {
+    private Function<XmlPullParser, ParentXMLFilter> filterCreator;
+
+    @BeforeEach
+    void reset() {
+        filterCreator = null;
+    }
+
     @Override
-    protected ParentXMLFilter getFilter( Consumer<LexicalHandler> lexicalHandlerConsumer )
-        throws TransformerException, SAXException, ParserConfigurationException
+    protected ParentXMLFilter getFilter( XmlPullParser parser )
     {
-        ParentXMLFilter filter = new ParentXMLFilter( x -> Optional.of( new RelativeProject( "GROUPID",
-                                                                                           "ARTIFACTID",
-                                                                                           "1.0.0" ) ) );
-        filter.setProjectPath( Paths.get( "pom.xml").toAbsolutePath() );
-        lexicalHandlerConsumer.accept( filter );
+        Function<XmlPullParser, ParentXMLFilter> filterCreator =
+            (this.filterCreator != null ? this.filterCreator : this::createFilter);
+        return filterCreator.apply(parser);
+    }
+
+    protected ParentXMLFilter createFilter( XmlPullParser parser ) {
+        return createFilter( parser,
+                x -> Optional.of(new RelativeProject("GROUPID", "ARTIFACTID", "1.0.0")),
+                Paths.get( "pom.xml").toAbsolutePath() );
+    }
 
+    protected ParentXMLFilter createFilter( XmlPullParser parser, Function<Path, Optional<RelativeProject>> pathMapper, Path projectPath ) {
+        ParentXMLFilter filter = new ParentXMLFilter( parser, pathMapper, projectPath );
         return filter;
     }
 
@@ -52,7 +63,7 @@ public class ParentXMLFilterTest
     public void testMinimum()
         throws Exception
     {
-        String input = "<parent/>";
+        String input = "<project><parent /></project>";
         String expected = input;
         String actual = transform( input );
         assertEquals( expected, actual );
@@ -62,11 +73,11 @@ public class ParentXMLFilterTest
     public void testNoRelativePath()
         throws Exception
     {
-        String input = "<parent>"
+        String input = "<project><parent>"
             + "<groupId>GROUPID</groupId>"
             + "<artifactId>ARTIFACTID</artifactId>"
             + "<version>VERSION</version>"
-            + "</parent>";
+            + "</parent></project>";
         String expected = input;
 
         String actual = transform( input );
@@ -78,15 +89,19 @@ public class ParentXMLFilterTest
     public void testDefaultRelativePath()
         throws Exception
     {
-        String input = "<parent>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "</parent>";
-        String expected = "<parent>"
-                        + "<groupId>GROUPID</groupId>"
-                        + "<artifactId>ARTIFACTID</artifactId>"
-                        + "<version>1.0.0</version>"
-                        + "</parent>";
+        String input = "<project>\n"
+            + "  <parent>\n"
+            + "    <groupId>GROUPID</groupId>\n"
+            + "    <artifactId>ARTIFACTID</artifactId>\n"
+            + "  </parent>\n"
+            + "</project>";
+        String expected = "<project>" + System.lineSeparator()
+                        + "  <parent>" + System.lineSeparator()
+                        + "    <groupId>GROUPID</groupId>" + System.lineSeparator()
+                        + "    <artifactId>ARTIFACTID</artifactId>" + System.lineSeparator()
+                        + "    <version>1.0.0</version>" + System.lineSeparator()
+                        + "  </parent>" + System.lineSeparator()
+                        + "</project>";
 
         String actual = transform( input );
 
@@ -103,16 +118,16 @@ public class ParentXMLFilterTest
     public void testEmptyRelativePathNoVersion()
         throws Exception
     {
-        String input = "<parent>"
+        String input = "<project><parent>"
             + "<groupId>GROUPID</groupId>"
             + "<artifactId>ARTIFACTID</artifactId>"
             + "<relativePath></relativePath>"
-            + "</parent>";
-        String expected = "<parent>"
+            + "</parent></project>";
+        String expected = "<project><parent>"
                         + "<groupId>GROUPID</groupId>"
                         + "<artifactId>ARTIFACTID</artifactId>"
-                        + "<relativePath/>" // SAX optimization, however "" != null ...
-                        + "</parent>";
+                        + "<relativePath />" // SAX optimization, however "" != null ...
+                        + "</parent></project>";
 
         String actual = transform( input );
 
@@ -123,17 +138,17 @@ public class ParentXMLFilterTest
     public void testNoVersion()
         throws Exception
     {
-        String input = "<parent>"
+        String input = "<project><parent>"
             + "<groupId>GROUPID</groupId>"
             + "<artifactId>ARTIFACTID</artifactId>"
             + "<relativePath>RELATIVEPATH</relativePath>"
-            + "</parent>";
-        String expected = "<parent>"
+            + "</parent></project>";
+        String expected = "<project><parent>"
                         + "<groupId>GROUPID</groupId>"
                         + "<artifactId>ARTIFACTID</artifactId>"
                         + "<relativePath>RELATIVEPATH</relativePath>"
                         + "<version>1.0.0</version>"
-                        + "</parent>";
+                        + "</parent></project>";
 
         String actual = transform( input );
 
@@ -144,17 +159,16 @@ public class ParentXMLFilterTest
     public void testInvalidRelativePath()
         throws Exception
     {
-        ParentXMLFilter filter = new ParentXMLFilter( x -> Optional.ofNullable( null ) );
-        filter.setProjectPath( Paths.get( "pom.xml").toAbsolutePath() );
+        filterCreator = parser -> createFilter(parser, x -> Optional.ofNullable( null ), Paths.get( "pom.xml").toAbsolutePath() );
 
-        String input = "<parent>"
+        String input = "<project><parent>"
             + "<groupId>GROUPID</groupId>"
             + "<artifactId>ARTIFACTID</artifactId>"
             + "<relativePath>RELATIVEPATH</relativePath>"
-            + "</parent>";
+            + "</parent></project>";
         String expected = input;
 
-        String actual = transform( input, filter );
+        String actual = transform( input );
 
         assertEquals( expected, actual );
     }
@@ -163,18 +177,18 @@ public class ParentXMLFilterTest
     public void testRelativePathAndVersion()
         throws Exception
     {
-        String input = "<parent>"
+        String input = "<project><parent>"
             + "<groupId>GROUPID</groupId>"
             + "<artifactId>ARTIFACTID</artifactId>"
             + "<relativePath>RELATIVEPATH</relativePath>"
             + "<version>1.0.0</version>"
-            + "</parent>";
-        String expected = "<parent>"
+            + "</parent></project>";
+        String expected = "<project><parent>"
                         + "<groupId>GROUPID</groupId>"
                         + "<artifactId>ARTIFACTID</artifactId>"
                         + "<relativePath>RELATIVEPATH</relativePath>"
                         + "<version>1.0.0</version>"
-                        + "</parent>";
+                        + "</parent></project>";
 
         String actual = transform( input );
 
@@ -185,17 +199,20 @@ public class ParentXMLFilterTest
     public void testWithWeirdNamespace()
         throws Exception
     {
-        String input = "<relativePath:parent xmlns:relativePath=\"relativePath\">"
+        String input = "<relativePath:project xmlns:relativePath=\"relativePath\">"
+            + "<relativePath:parent>"
             + "<relativePath:groupId>GROUPID</relativePath:groupId>"
             + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>"
             + "<relativePath:relativePath>RELATIVEPATH</relativePath:relativePath>"
-            + "</relativePath:parent>";
-        String expected = "<relativePath:parent xmlns:relativePath=\"relativePath\">"
+            + "</relativePath:parent></relativePath:project>";
+        String expected = "<relativePath:project xmlns:relativePath=\"relativePath\">"
+                        + "<relativePath:parent>"
                         + "<relativePath:groupId>GROUPID</relativePath:groupId>"
                         + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>"
                         + "<relativePath:relativePath>RELATIVEPATH</relativePath:relativePath>"
                         + "<relativePath:version>1.0.0</relativePath:version>"
-                        + "</relativePath:parent>";
+                        + "</relativePath:parent>"
+                        + "</relativePath:project>";
 
         String actual = transform( input );
 
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ReactorDependencyXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ReactorDependencyXMLFilterTest.java
index 69b4783..0304ea6 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ReactorDependencyXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ReactorDependencyXMLFilterTest.java
@@ -19,27 +19,29 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
-import java.util.function.Consumer;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerException;
+import java.util.function.BiFunction;
 
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
+
+import static org.xmlunit.assertj.XmlAssert.assertThat;
 
 public class ReactorDependencyXMLFilterTest
     extends AbstractXMLFilterTests
 {
+    private BiFunction<String, String, String> reactorVersionMapper;
+
+    @BeforeEach
+    protected void reset() {
+        reactorVersionMapper = null;
+    }
+
     @Override
-    protected ReactorDependencyXMLFilter getFilter( Consumer<LexicalHandler> lexicalHandlerConsumer )
-        throws TransformerException, SAXException, ParserConfigurationException
+    protected ReactorDependencyXMLFilter getFilter(XmlPullParser parser)
     {
-        ReactorDependencyXMLFilter filter = new ReactorDependencyXMLFilter( (g, a) -> "1.0.0" );
-        lexicalHandlerConsumer.accept( filter );
-        return filter;
+        return new ReactorDependencyXMLFilter( parser,
+                reactorVersionMapper != null ? reactorVersionMapper : (g, a) -> "1.0.0" );
     }
 
     @Test
@@ -62,7 +64,7 @@ public class ReactorDependencyXMLFilterTest
     public void testManagedDependency()
         throws Exception
     {
-        ReactorDependencyXMLFilter filter = new ReactorDependencyXMLFilter( (g, a) -> null );
+        reactorVersionMapper = (g, a) -> null;
 
         String input = "<dependency>"
             + "<groupId>GROUPID</groupId>"
@@ -70,7 +72,7 @@ public class ReactorDependencyXMLFilterTest
             + "</dependency>";
         String expected = input;
 
-        String actual = transform( input, filter );
+        String actual = transform( input );
 
         assertThat( actual ).isEqualTo( expected );
     }
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/RelativePathXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/RelativePathXMLFilterTest.java
index bc1c345..bfe3582 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/RelativePathXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/RelativePathXMLFilterTest.java
@@ -19,17 +19,18 @@ package org.apache.maven.model.transform;
  * under the License.
  */
 
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 import org.junit.jupiter.api.Test;
 
+import static org.xmlunit.assertj.XmlAssert.assertThat;
+
 public class RelativePathXMLFilterTest
     extends AbstractXMLFilterTests
 {
     @Override
-    protected RelativePathXMLFilter getFilter()
+    protected RelativePathXMLFilter getFilter(XmlPullParser parser)
     {
-        return new RelativePathXMLFilter();
+        return new RelativePathXMLFilter(parser);
     }
 
     @Test
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/ChainedFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/ChainedFilterTest.java
deleted file mode 100644
index 028b9e5..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/ChainedFilterTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-
-import javax.xml.transform.Transformer;
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamResult;
-
-import org.junit.jupiter.api.Test;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-/**
- * A small example of a pipeline of 2 XML Filters, to understand how to get the expected result
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class ChainedFilterTest
-{
-
-    @Test
-    public void test()
-        throws Exception
-    {
-        String input = "<project><!-- aBc --><name>dEf</name></project>";
-
-        SAXTransformerFactory transformerFactory = (SAXTransformerFactory) Factories.newTransformerFactory();
-        TransformerHandler transformerHandler = transformerFactory.newTransformerHandler();
-
-        Writer writer = new StringWriter();
-        StreamResult result = new StreamResult( writer );
-        transformerHandler.setResult( result );
-
-        SAXResult transformResult = new SAXResult( transformerHandler );
-
-        // Watch the order of filters! In reverse order the values would be 'AweSome'
-        AbstractSAXFilter filter = new Awesome();
-
-        // AbstractSAXFilter doesn't have a constructor with XMLReader, otherwise the LexicalHandler pipeline will be broken
-        filter.setParent( Factories.newXMLReader() );
-
-        // LexicalHandler of transformerResult must be the first filter
-        transformResult.setLexicalHandler( filter );
-
-        filter = new ChangeCase( filter );
-        // LexicalHandler on last filter must be the transformerHandler
-        filter.setLexicalHandler( transformerHandler );
-
-        SAXSource transformSource = new SAXSource( filter, new InputSource( new StringReader( input ) ) );
-
-        Transformer transformer = transformerFactory.newTransformer();
-        transformer.transform( transformSource, transformResult );
-
-        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-            + "<project><!--AWESOME--><name>awesome</name></project>";
-        assertThat( writer.toString() ).and( expected ).areIdentical();
-    }
-
-    static class ChangeCase
-        extends AbstractSAXFilter
-    {
-
-        public ChangeCase()
-        {
-            super();
-        }
-
-        public ChangeCase( AbstractSAXFilter parent )
-        {
-            super( parent );
-        }
-
-        @Override
-        public void comment( char[] ch, int start, int length )
-            throws SAXException
-        {
-            String s = new String( ch, start, length ).toUpperCase();
-            super.comment( s.toCharArray(), 0, s.length() );
-        }
-
-        @Override
-        public void characters( char[] ch, int start, int length )
-            throws SAXException
-        {
-            String s = new String( ch, start, length ).toLowerCase();
-            super.characters( s.toCharArray(), 0, s.length() );
-        }
-    }
-
-    static class Awesome
-        extends AbstractSAXFilter
-    {
-
-        public Awesome()
-        {
-            super();
-        }
-
-        public Awesome( AbstractSAXFilter parent )
-        {
-            super( parent );
-        }
-
-        @Override
-        public void comment( char[] ch, int start, int length )
-            throws SAXException
-        {
-            String s = "AweSome";
-            super.comment( s.toCharArray(), 0, s.length() );
-        }
-
-        @Override
-        public void characters( char[] ch, int start, int length )
-            throws SAXException
-        {
-            String s = "AweSome";
-            super.characters( s.toCharArray(), 0, s.length() );
-        }
-    }
-
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/CommentRenormalizerTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/CommentRenormalizerTest.java
deleted file mode 100644
index c663741..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/CommentRenormalizerTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-
-import org.xml.sax.ext.LexicalHandler;
-
-public class CommentRenormalizerTest
-{
-    private LexicalHandler lexicalHandler = mock( LexicalHandler.class );
-
-    @ParameterizedTest
-    @ValueSource( strings = { "\n", "\r\n", "\r" } )
-    public void singleLine( String lineSeparator )
-        throws Exception
-    {
-        CommentRenormalizer commentRenormalizer = new CommentRenormalizer( lexicalHandler, lineSeparator );
-
-        char[] ch = "single line".toCharArray();
-
-        commentRenormalizer.comment( ch, 0, ch.length );
-
-        verify( lexicalHandler ).comment( ch, 0, ch.length );
-    }
-
-    @ParameterizedTest
-    @ValueSource( strings = { "\n", "\r\n", "\r" } )
-    public void multiLine( String lineSeparator )
-        throws Exception
-    {
-        CommentRenormalizer commentRenormalizer = new CommentRenormalizer( lexicalHandler, lineSeparator );
-
-        String text = "I%sam%sthe%sbest%s";
-
-        char[] chIn = String.format( text, "\n", "\n", "\n", "\n" ).toCharArray();
-        char[] chOut = String.format( text, lineSeparator, lineSeparator, lineSeparator, lineSeparator ).toCharArray();
-
-        commentRenormalizer.comment( chIn, 0, chIn.length );
-
-        verify( lexicalHandler ).comment( chOut, 0, chOut.length );
-    }
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/SAXEventUtilsTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/SAXEventUtilsTest.java
deleted file mode 100644
index 8ec4bec..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/sax/SAXEventUtilsTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.apache.maven.model.transform.sax;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import static org.hamcrest.CoreMatchers.is;
-
-import org.junit.jupiter.api.Test;
-
-public class SAXEventUtilsTest
-{
-    @Test
-    public void replaceWithNamespace()
-    {
-        assertThat( SAXEventUtils.renameQName( "org:bar", "com" ), is( "org:com" ) );
-    }
-
-    @Test
-    public void replaceWithoutNamespace()
-    {
-        assertThat( SAXEventUtils.renameQName( "bar", "com" ), is( "com" ) );
-    }
-}

[maven] 04/04: Fix entity replacement

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-7182
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 654c93bd13a3a449508ce0c6d772fc5f15a17f58
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Jul 29 10:01:49 2021 +0200

    Fix entity replacement
---
 .../src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java
index c583a18..f2243c8 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java
@@ -86,7 +86,7 @@ public class XmlUtils
                     serializer.cdsect( parser.getText() );
                     break;
                 case XmlPullParser.ENTITY_REF:
-                    serializer.entityRef( parser.getText() );
+                    serializer.entityRef( parser.getName() );
                     break;
                 case XmlPullParser.IGNORABLE_WHITESPACE:
                     serializer.ignorableWhitespace( normalize( parser.getText() ) );

[maven] 02/04: Fix minor issues after review

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-7182
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 8559fcc8edfba237d8173f745bcfc4cd5b1fed10
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Jul 22 11:01:06 2021 +0200

    Fix minor issues after review
---
 .../apache/maven/model/io/DefaultModelReader.java  | 52 +++++++++++++++-------
 .../transform/BuildToRawPomXMLFilterFactory.java   |  4 +-
 .../maven/model/transform/FastForwardFilter.java   |  5 ++-
 .../RawToConsumerPomXMLFilterFactory.java          |  7 +--
 .../model/transform/RelativePathXMLFilter.java     |  7 +--
 .../model/transform/ModulesXMLFilterTest.java      |  2 +-
 6 files changed, 48 insertions(+), 29 deletions(-)

diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
index fd4cb8a..f55039b 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
@@ -59,6 +59,10 @@ public class DefaultModelReader
     @Inject
     private ModelSourceTransformer transformer;
 
+    private Method readMethod;
+
+    private Method readMethodEx;
+
     public void setTransformer( ModelSourceTransformer transformer )
     {
         this.transformer = transformer;
@@ -131,33 +135,20 @@ public class DefaultModelReader
             parser.setInput( reader );
 
             TransformerContext context = getTransformerContext( options );
-            if ( context != null )
-            {
-                parser = transformer.transform( parser, pomFile, context );
-            }
+            XmlPullParser transformingParser = context != null
+                    ? transformer.transform( parser, pomFile, context ) : parser;
 
-            // TODO: avoid or at least cache reflection data
             InputSource source = getSource( options );
             boolean strict = isStrict( options );
             try
             {
                 if ( source != null )
                 {
-                    MavenXpp3ReaderEx mr = new MavenXpp3ReaderEx();
-                    Method readMethod = mr.getClass().getDeclaredMethod( "read",
-                            XmlPullParser.class, boolean.class, InputSource.class );
-                    readMethod.setAccessible( true );
-                    Object model = readMethod.invoke( mr, parser, strict, source );
-                    return (Model) model;
+                    return readModelEx( transformingParser, source, strict );
                 }
                 else
                 {
-                    MavenXpp3Reader mr = new MavenXpp3Reader();
-                    Method readMethod = mr.getClass().getDeclaredMethod( "read",
-                            XmlPullParser.class, boolean.class );
-                    readMethod.setAccessible( true );
-                    Object model = readMethod.invoke( mr, parser, strict );
-                    return (Model) model;
+                    return readModel( transformingParser, strict );
                 }
             }
             catch ( InvocationTargetException e )
@@ -184,4 +175,31 @@ public class DefaultModelReader
         }
     }
 
+    private Model readModel( XmlPullParser parser, boolean strict )
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
+    {
+        if ( readMethod == null )
+        {
+            readMethod = MavenXpp3Reader.class.getDeclaredMethod( "read", XmlPullParser.class, boolean.class );
+            readMethod.setAccessible( true );
+        }
+        MavenXpp3Reader mr = new MavenXpp3Reader();
+        Object model = readMethod.invoke( mr, parser, strict );
+        return ( Model ) model;
+    }
+
+    private Model readModelEx( XmlPullParser parser, InputSource source, boolean strict )
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
+    {
+        if ( readMethodEx == null )
+        {
+            readMethodEx = MavenXpp3ReaderEx.class.getDeclaredMethod( "read",
+                    XmlPullParser.class, boolean.class, InputSource.class );
+            readMethodEx.setAccessible( true );
+        }
+        MavenXpp3ReaderEx mr = new MavenXpp3ReaderEx();
+        Object model = readMethodEx.invoke( mr, parser, strict, source );
+        return ( Model ) model;
+    }
+
 }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
index 4673102..3d1f1a2 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
@@ -50,9 +50,11 @@ public class BuildToRawPomXMLFilterFactory
      *
      * @param projectFile will be used by ConsumerPomXMLFilter to get the right filter
      */
-    public final XmlPullParser get( XmlPullParser parser, Path projectFile )
+    public final XmlPullParser get( XmlPullParser orgParser, Path projectFile )
 
     {
+        XmlPullParser parser = orgParser;
+
         if ( getDependencyKeyToVersionMapper() != null )
         {
             parser = new ReactorDependencyXMLFilter( parser, getDependencyKeyToVersionMapper() );
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
index c5c2171..91977c0 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
@@ -29,7 +29,7 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 /**
  * This filter will skip all following filters and write directly to the output.
- * Should be used in case of a DOM that should not be effected by other filters, even though the elements match
+ * Should be used in case of a DOM that should not be effected by other filters, even though the elements match.
  *
  * @author Robert Scholte
  * @author Guillaume Nodet
@@ -90,7 +90,8 @@ class FastForwardFilter extends BufferingParser
         }
         else if ( xmlPullParser.getEventType() == END_TAG )
         {
-            if ( --domDepth == 0 )
+            domDepth--;
+            if ( domDepth == 0 )
             {
                 enable();
             }
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
index aa0c432..e36342b 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
@@ -24,7 +24,7 @@ import java.nio.file.Path;
 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 
 /**
- *
+ * @author Guillaume Nodet
  * @author Robert Scholte
  * @since 4.0.0
  */
@@ -37,10 +37,11 @@ public class RawToConsumerPomXMLFilterFactory
         this.buildPomXMLFilterFactory = buildPomXMLFilterFactory;
     }
 
-    public final XmlPullParser get( XmlPullParser parser, Path projectPath )
+    public final XmlPullParser get( XmlPullParser orgParser, Path projectPath )
     {
-        parser = buildPomXMLFilterFactory.get( parser, projectPath );
+        XmlPullParser parser = orgParser;
 
+        parser = buildPomXMLFilterFactory.get( parser, projectPath );
 
         // Ensure that xs:any elements aren't touched by next filters
         parser = new FastForwardFilter( parser );
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
index 4368f2c..3064a29 100644
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
+++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
@@ -59,12 +59,9 @@ public class RelativePathXMLFilter extends NodeBufferingParser
                 skip = false;
                 event = null;
             }
-            else
+            else if ( skip )
             {
-                if ( skip )
-                {
-                    event = null;
-                }
+                event = null;
             }
             if ( prev != null )
             {
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
index b3b31f5..0080788 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
@@ -29,7 +29,7 @@ public class ModulesXMLFilterTest
 {
 
     @Override
-    protected ModulesXMLFilter getFilter(XmlPullParser parser)
+    protected ModulesXMLFilter getFilter( XmlPullParser parser )
     {
         return new ModulesXMLFilter( parser );
     }

[maven] 03/04: Avoid changing parameter value

Posted by rf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rfscholte pushed a commit to branch MNG-7182
in repository https://gitbox.apache.org/repos/asf/maven.git

commit f2c5b92bad4c1a5ce77559a2b2a2398a924d1549
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Jul 22 11:08:14 2021 +0200

    Avoid changing parameter value
---
 .../org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java  | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
index 3ecf255..ee77d12 100644
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
+++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
@@ -33,7 +33,7 @@ import org.junit.jupiter.api.Test;
 public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
 {
     @Override
-    protected XmlPullParser getFilter( XmlPullParser parser )
+    protected XmlPullParser getFilter( XmlPullParser orgParser )
     {
         final BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory = new BuildToRawPomXMLFilterFactory( true )
         {
@@ -69,8 +69,8 @@ public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
 
         };
 
-        parser = new RawToConsumerPomXMLFilterFactory( buildPomXMLFilterFactory )
-                        .get( parser, Paths.get( "pom.xml" ) );
+        XmlPullParser parser = new RawToConsumerPomXMLFilterFactory( buildPomXMLFilterFactory )
+                        .get( orgParser, Paths.get( "pom.xml" ) );
         return parser;
     }