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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 1e72b804794b CAMEL-25078: camel-xml-jaxp - XML type converters: fix 
bugs found in a deep review (#26968)
1e72b804794b is described below

commit 1e72b804794b2b850567efdb5ec9709d37703b89
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 28 22:41:11 2026 +0200

    CAMEL-25078: camel-xml-jaxp - XML type converters: fix bugs found in a deep 
review (#26968)
    
    - XMLStreamReader to InputStream/Reader: a read of 0 bytes returns 0 
(readAllBytes was cut at 16 KB),
      the writer is flushed (another charset than utf-8 was empty with jdk 
stax), attributes without a
      namespace work in the Reader variant, and a reader positioned at an 
element keeps that element
    - a text node in mixed content converts to String (was ClassCastException), 
and a list of text nodes
      is not repeated
    - an attribute node converts to its value
    - a file to XMLStreamReader/XMLEventReader uses the encoding of the xml 
declaration
    - XmlLineNumberParser with root names handles elements after the root (also 
in camel-route-parser)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../camel/parser/helper/XmlLineNumberParser.java   |  13 +-
 .../converter/jaxp/XmlConvertersEdgeCasesTest.java | 133 +++++++++++++++++++++
 .../apache/camel/converter/jaxp/DomConverter.java  |  15 ++-
 .../apache/camel/converter/jaxp/StaxConverter.java |  18 +--
 .../converter/jaxp/XMLStreamReaderInputStream.java |  93 ++++++++------
 .../converter/jaxp/XMLStreamReaderReader.java      |  90 ++++++++------
 .../apache/camel/util/xml/XmlLineNumberParser.java |  13 +-
 7 files changed, 281 insertions(+), 94 deletions(-)

diff --git 
a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/XmlLineNumberParser.java
 
b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/XmlLineNumberParser.java
index 537c6d6f710f..9ae73d7f77d3 100644
--- 
a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/XmlLineNumberParser.java
+++ 
b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/XmlLineNumberParser.java
@@ -137,6 +137,7 @@ public final class XmlLineNumberParser {
         return new DefaultHandler() {
             private Locator locator;
             private boolean found;
+            private boolean done;
             private final Map<String, String> localNs = new HashMap<>();
             private final Map<String, String> anonymousNs = new 
LinkedHashMap<>();
 
@@ -160,6 +161,10 @@ public final class XmlLineNumberParser {
                     final String uri, final String localName, final String 
qName, final Attributes attributes) {
                 addTextIfNeeded();
 
+                if (done) {
+                    // only the first root element is parsed (there can only 
be one document element)
+                    return;
+                }
                 if (rootNames != null && !found) {
                     if (isRootName(qName)) {
                         found = true;
@@ -232,6 +237,11 @@ public final class XmlLineNumberParser {
                     if (elementStack.isEmpty()) {
                         // Is this the root element?
                         doc.appendChild(closedEl);
+                        if (rootNames != null) {
+                            // the root element is done, so elements after it 
are not parsed
+                            found = false;
+                            done = true;
+                        }
                     } else {
                         final Element parentEl = elementStack.peek();
                         parentEl.appendChild(closedEl);
@@ -264,8 +274,9 @@ public final class XmlLineNumberParser {
                     if (el != null) {
                         final Node textNode = 
doc.createTextNode(textBuffer.toString());
                         el.appendChild(textNode);
-                        textBuffer.delete(0, textBuffer.length());
                     }
+                    // text outside the elements that are parsed is not added 
to the next element
+                    textBuffer.delete(0, textBuffer.length());
                 }
             }
         };
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConvertersEdgeCasesTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConvertersEdgeCasesTest.java
new file mode 100644
index 000000000000..24c92924dac2
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConvertersEdgeCasesTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+package org.apache.camel.converter.jaxp;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.apache.camel.util.xml.XmlLineNumberParser;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class XmlConvertersEdgeCasesTest {
+
+    // the jdk implementation of stax (camel-core tests have woodstox on the 
classpath)
+    private static final XMLInputFactory JDK_INPUT = 
XMLInputFactory.newDefaultFactory();
+    private static final XMLOutputFactory JDK_OUTPUT = 
XMLOutputFactory.newDefaultFactory();
+
+    @TempDir
+    File tempDir;
+
+    private static XMLStreamReader reader(String xml) throws Exception {
+        return JDK_INPUT.createXMLStreamReader(new StringReader(xml));
+    }
+
+    @Test
+    public void testReadAllBytesOfLargeDocument() throws Exception {
+        StringBuilder sb = new StringBuilder("<a>");
+        for (int i = 0; i < 2000; i++) {
+            sb.append("<b>").append(i).append("</b>");
+        }
+        sb.append("</a>");
+
+        InputStream is = new XMLStreamReaderInputStream(reader(sb.toString()), 
"utf-8", JDK_OUTPUT);
+        assertThat(is.read(new byte[1], 0, 0)).isZero();
+        String out = new String(is.readAllBytes(), StandardCharsets.UTF_8);
+        assertThat(out).endsWith("</a>").contains("<b>1999</b>");
+    }
+
+    @Test
+    public void testInputStreamWithOtherCharset() throws Exception {
+        InputStream is = new XMLStreamReaderInputStream(reader("<a>café</a>"), 
"ISO-8859-1", JDK_OUTPUT);
+        String out = new String(is.readAllBytes(), 
StandardCharsets.ISO_8859_1);
+        assertThat(out).contains("<a>café</a>");
+    }
+
+    @Test
+    public void testReaderWithUnqualifiedAttribute() throws Exception {
+        StringWriter sw = new StringWriter();
+        new XMLStreamReaderReader(reader("<a x=\"1\"><b>t</b></a>"), 
JDK_OUTPUT).transferTo(sw);
+        assertThat(sw.toString()).contains("<a x=\"1\"><b>t</b></a>");
+    }
+
+    @Test
+    public void testReaderPositionedAtElement() throws Exception {
+        XMLStreamReader r = reader("<a><b>t</b></a>");
+        r.nextTag();
+        InputStream is = new XMLStreamReaderInputStream(r, "utf-8", 
JDK_OUTPUT);
+        assertThat(new String(is.readAllBytes(), 
StandardCharsets.UTF_8)).contains("<a><b>t</b></a>");
+    }
+
+    @Test
+    public void testTextNodesInMixedContent() throws Exception {
+        Document doc = new XmlConverter().toDOMDocument("<a>foo<b/>bar</a>", 
null);
+        NodeList nl = (NodeList) 
XPathFactory.newInstance().newXPath().evaluate("/a/text()", doc, 
XPathConstants.NODESET);
+
+        DomConverter dom = new DomConverter();
+        assertThat(dom.toString(nl, null)).isEqualTo("foobar");
+        assertThat(dom.toString(nl.item(0), null)).isEqualTo("foo");
+    }
+
+    @Test
+    public void testAttrToString() throws Exception {
+        Document doc = new XmlConverter().toDOMDocument("<a x=\"1\"/>", null);
+        Attr attr = doc.getDocumentElement().getAttributeNode("x");
+        assertThat(new DomConverter().toString((Node) attr, 
null)).isEqualTo("1");
+    }
+
+    @Test
+    public void testStreamReaderFromFileUsesDeclaredEncoding() throws 
Exception {
+        File file = new File(tempDir, "latin1.xml");
+        Files.write(file.toPath(), "<?xml version=\"1.0\" 
encoding=\"ISO-8859-1\"?><a>café</a>"
+                .getBytes(StandardCharsets.ISO_8859_1));
+
+        XMLStreamReader r = new StaxConverter().createXMLStreamReader(file, 
null);
+        try {
+            r.nextTag();
+            assertThat(r.getElementText()).isEqualTo("café");
+        } finally {
+            r.close();
+        }
+    }
+
+    @Test
+    public void testLineNumberParserWithElementsAfterRoot() throws Exception {
+        String xml = "<beans>\n <camelContext><route/></camelContext>\n <bean 
id=\"b\">\n hello\n </bean>\n</beans>";
+        Document doc = XmlLineNumberParser.parseXml(
+                new 
ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)), null, 
"camelContext", null);
+        
assertThat(doc.getDocumentElement().getNodeName()).isEqualTo("camelContext");
+        
assertThat(doc.getDocumentElement().getTextContent()).doesNotContain("hello");
+    }
+}
diff --git 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/DomConverter.java
 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/DomConverter.java
index dda5c8265dc4..7cfc31a26416 100644
--- 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/DomConverter.java
+++ 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/DomConverter.java
@@ -69,7 +69,9 @@ public final class DomConverter {
             int size = nodeList.getLength();
             for (int i = 0; i < size; i++) {
                 Node node = nodeList.item(i);
-                String s = toString(node, exchange);
+                // the text nodes of the list are appended each (and not 
joined with their siblings, which may be
+                // in the list as well)
+                String s = node instanceof Text ? node.getNodeValue() : 
toString(node, exchange);
                 if (org.apache.camel.util.ObjectHelper.isNotEmpty(s)) {
                     found = true;
                     buffer.append(s);
@@ -90,14 +92,17 @@ public final class DomConverter {
     public String toString(Node node, Exchange exchange) throws 
TransformerException {
         String s;
         if (node instanceof Text textNode) {
+            // join the adjacent text nodes (such as text and cdata), but not 
the text after an element or comment
             StringBuilder b = new StringBuilder(128);
             b.append(textNode.getNodeValue());
-            textNode = (Text) textNode.getNextSibling();
-            while (textNode != null) {
-                b.append(textNode.getNodeValue());
-                textNode = (Text) textNode.getNextSibling();
+            Node sibling = textNode.getNextSibling();
+            while (sibling instanceof Text) {
+                b.append(sibling.getNodeValue());
+                sibling = sibling.getNextSibling();
             }
             s = b.toString();
+        } else if (node instanceof Attr attr) {
+            s = attr.getValue();
         } else {
             s = xml.toString(new DOMSource(node), exchange);
         }
diff --git 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
index 294a8f1e38de..13307bf2a47f 100644
--- 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
+++ 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/StaxConverter.java
@@ -153,13 +153,8 @@ public class StaxConverter {
     @Converter(order = 8)
     public XMLStreamReader createXMLStreamReader(File file, Exchange exchange)
             throws XMLStreamException, FileNotFoundException {
-        XMLInputFactory factory = getInputFactory();
-        try {
-            return factory.createXMLStreamReader(IOHelper.buffered(new 
FileInputStream(file)),
-                    ExchangeHelper.getCharsetName(exchange));
-        } finally {
-            returnXMLInputFactory(factory);
-        }
+        // same as from a stream (the encoding of the xml declaration is used 
unless the exchange has a charset)
+        return createXMLStreamReader(new FileInputStream(file), exchange);
     }
 
     @Converter(order = 9)
@@ -209,13 +204,8 @@ public class StaxConverter {
 
     @Converter(order = 13)
     public XMLEventReader createXMLEventReader(File file, Exchange exchange) 
throws XMLStreamException, FileNotFoundException {
-        XMLInputFactory factory = getInputFactory();
-        try {
-            return factory.createXMLEventReader(IOHelper.buffered(new 
FileInputStream(file)),
-                    ExchangeHelper.getCharsetName(exchange));
-        } finally {
-            returnXMLInputFactory(factory);
-        }
+        // same as from a stream (the encoding of the xml declaration is used 
unless the exchange has a charset)
+        return createXMLEventReader(new FileInputStream(file), exchange);
     }
 
     @Converter(order = 14)
diff --git 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
index 583a74d2b027..f548b68e624b 100644
--- 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
+++ 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderInputStream.java
@@ -38,6 +38,7 @@ class XMLStreamReaderInputStream extends InputStream {
     private final byte[] buffer;
     private final String charset;
     private int bpos;
+    private boolean started;
 
     XMLStreamReaderInputStream(XMLStreamReader reader, String charset, 
XMLOutputFactory outfactory) {
         this.reader = reader;
@@ -63,6 +64,9 @@ class XMLStreamReaderInputStream extends InputStream {
 
     @Override
     public int read(byte[] b, int off, int len) throws IOException {
+        if (len == 0) {
+            return 0;
+        }
         int tlen = 0;
         while (len > 0) {
             int n = ensureBuffering(len);
@@ -89,47 +93,22 @@ class XMLStreamReaderInputStream extends InputStream {
         try {
 
             // very first event
-            if (XMLStreamConstants.START_DOCUMENT == reader.getEventType()) {
-                writer.writeStartDocument(charset, "1.0");
+            if (!started) {
+                started = true;
+                int event = reader.getEventType();
+                if (XMLStreamConstants.START_DOCUMENT == event) {
+                    writer.writeStartDocument(charset, "1.0");
+                } else if (XMLStreamConstants.START_ELEMENT == event) {
+                    // the reader is already positioned at an element (such as 
by nextTag)
+                    writeEvent(event);
+                }
+                writer.flush();
             }
             if (chunk.size() < buffer.length) {
                 while (reader.hasNext()) {
-                    int code = reader.next();
-                    switch (code) {
-                        case XMLStreamConstants.END_DOCUMENT:
-                            writer.writeEndDocument();
-                            break;
-                        case XMLStreamConstants.START_ELEMENT:
-                            QName qname = reader.getName();
-                            writer.writeStartElement(qname.getPrefix(), 
qname.getLocalPart(), qname.getNamespaceURI());
-                            for (int i = 0; i < reader.getAttributeCount(); 
i++) {
-                                String namespaceUri = 
reader.getAttributeNamespace(i);
-                                
writer.writeAttribute(reader.getAttributePrefix(i), namespaceUri == null ? "" : 
namespaceUri,
-                                        reader.getAttributeLocalName(i),
-                                        reader.getAttributeValue(i));
-                            }
-                            for (int i = 0; i < reader.getNamespaceCount(); 
i++) {
-                                String namespacePrefix = 
reader.getNamespacePrefix(i);
-                                String namespaceURI = 
reader.getNamespaceURI(i);
-                                writer.writeNamespace(namespacePrefix == null 
? "" : namespacePrefix,
-                                        namespaceURI == null ? "" : 
namespaceURI);
-                            }
-                            break;
-                        case XMLStreamConstants.END_ELEMENT:
-                            writer.writeEndElement();
-                            break;
-                        case XMLStreamConstants.CHARACTERS:
-                            writer.writeCharacters(reader.getText());
-                            break;
-                        case XMLStreamConstants.COMMENT:
-                            writer.writeComment(reader.getText());
-                            break;
-                        case XMLStreamConstants.CDATA:
-                            writer.writeCData(reader.getText());
-                            break;
-                        default:
-                            break;
-                    }
+                    writeEvent(reader.next());
+                    // the writer may buffer (such as for another charset than 
utf-8)
+                    writer.flush();
 
                     // check if the chunk is full
                     final int csize = buffer.length - bpos;
@@ -155,6 +134,44 @@ class XMLStreamReaderInputStream extends InputStream {
         }
     }
 
+    private void writeEvent(int code) throws XMLStreamException {
+        switch (code) {
+            case XMLStreamConstants.END_DOCUMENT:
+                writer.writeEndDocument();
+                break;
+            case XMLStreamConstants.START_ELEMENT:
+                QName qname = reader.getName();
+                writer.writeStartElement(qname.getPrefix(), 
qname.getLocalPart(), qname.getNamespaceURI());
+                for (int i = 0; i < reader.getAttributeCount(); i++) {
+                    String namespaceUri = reader.getAttributeNamespace(i);
+                    String prefix = reader.getAttributePrefix(i);
+                    writer.writeAttribute(prefix == null ? "" : prefix, 
namespaceUri == null ? "" : namespaceUri,
+                            reader.getAttributeLocalName(i), 
reader.getAttributeValue(i));
+                }
+                for (int i = 0; i < reader.getNamespaceCount(); i++) {
+                    String namespacePrefix = reader.getNamespacePrefix(i);
+                    String namespaceURI = reader.getNamespaceURI(i);
+                    writer.writeNamespace(namespacePrefix == null ? "" : 
namespacePrefix,
+                            namespaceURI == null ? "" : namespaceURI);
+                }
+                break;
+            case XMLStreamConstants.END_ELEMENT:
+                writer.writeEndElement();
+                break;
+            case XMLStreamConstants.CHARACTERS:
+                writer.writeCharacters(reader.getText());
+                break;
+            case XMLStreamConstants.COMMENT:
+                writer.writeComment(reader.getText());
+                break;
+            case XMLStreamConstants.CDATA:
+                writer.writeCData(reader.getText());
+                break;
+            default:
+                break;
+        }
+    }
+
     static class TrimmableByteArrayOutputStream extends ByteArrayOutputStream {
         public void trim(int head, int tail) {
             System.arraycopy(buf, head, buf, 0, count - head - tail);
diff --git 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
index c112a7c32515..97b46cb4101e 100644
--- 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
+++ 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/converter/jaxp/XMLStreamReaderReader.java
@@ -37,6 +37,7 @@ class XMLStreamReaderReader extends Reader {
     private final TrimmableCharArrayWriter chunk;
     private final char[] buffer;
     private int bpos;
+    private boolean started;
 
     XMLStreamReaderReader(XMLStreamReader reader, XMLOutputFactory outfactory) 
{
         this.reader = reader;
@@ -56,6 +57,9 @@ class XMLStreamReaderReader extends Reader {
 
     @Override
     public int read(char[] cbuf, int off, int len) throws IOException {
+        if (len == 0) {
+            return 0;
+        }
         int tlen = 0;
         while (len > 0) {
             int n = ensureBuffering(len);
@@ -81,44 +85,22 @@ class XMLStreamReaderReader extends Reader {
         try {
 
             // very first event
-            if (XMLStreamConstants.START_DOCUMENT == reader.getEventType()) {
-                writer.writeStartDocument("utf-8", "1.0");
+            if (!started) {
+                started = true;
+                int event = reader.getEventType();
+                if (XMLStreamConstants.START_DOCUMENT == event) {
+                    writer.writeStartDocument("utf-8", "1.0");
+                } else if (XMLStreamConstants.START_ELEMENT == event) {
+                    // the reader is already positioned at an element (such as 
by nextTag)
+                    writeEvent(event);
+                }
+                writer.flush();
             }
             if (chunk.size() < buffer.length) {
                 while (reader.hasNext()) {
-                    int code = reader.next();
-                    switch (code) {
-                        case XMLStreamConstants.END_DOCUMENT:
-                            writer.writeEndDocument();
-                            break;
-                        case XMLStreamConstants.START_ELEMENT:
-                            QName qname = reader.getName();
-                            writer.writeStartElement(qname.getPrefix(), 
qname.getLocalPart(), qname.getNamespaceURI());
-                            for (int i = 0; i < reader.getAttributeCount(); 
i++) {
-                                writer.writeAttribute(
-                                        reader.getAttributePrefix(i), 
reader.getAttributeNamespace(i),
-                                        reader.getAttributeLocalName(i),
-                                        reader.getAttributeValue(i));
-                            }
-                            for (int i = 0; i < reader.getNamespaceCount(); 
i++) {
-                                
writer.writeNamespace(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
-                            }
-                            break;
-                        case XMLStreamConstants.END_ELEMENT:
-                            writer.writeEndElement();
-                            break;
-                        case XMLStreamConstants.CHARACTERS:
-                            writer.writeCharacters(reader.getText());
-                            break;
-                        case XMLStreamConstants.COMMENT:
-                            writer.writeComment(reader.getText());
-                            break;
-                        case XMLStreamConstants.CDATA:
-                            writer.writeCData(reader.getText());
-                            break;
-                        default:
-                            break;
-                    }
+                    writeEvent(reader.next());
+                    // the writer may buffer (such as for another charset than 
utf-8)
+                    writer.flush();
 
                     // check if the chunk is full
                     final int csize = buffer.length - bpos;
@@ -144,6 +126,44 @@ class XMLStreamReaderReader extends Reader {
         }
     }
 
+    private void writeEvent(int code) throws XMLStreamException {
+        switch (code) {
+            case XMLStreamConstants.END_DOCUMENT:
+                writer.writeEndDocument();
+                break;
+            case XMLStreamConstants.START_ELEMENT:
+                QName qname = reader.getName();
+                writer.writeStartElement(qname.getPrefix(), 
qname.getLocalPart(), qname.getNamespaceURI());
+                for (int i = 0; i < reader.getAttributeCount(); i++) {
+                    String namespaceUri = reader.getAttributeNamespace(i);
+                    String prefix = reader.getAttributePrefix(i);
+                    writer.writeAttribute(prefix == null ? "" : prefix, 
namespaceUri == null ? "" : namespaceUri,
+                            reader.getAttributeLocalName(i), 
reader.getAttributeValue(i));
+                }
+                for (int i = 0; i < reader.getNamespaceCount(); i++) {
+                    String namespacePrefix = reader.getNamespacePrefix(i);
+                    String namespaceURI = reader.getNamespaceURI(i);
+                    writer.writeNamespace(namespacePrefix == null ? "" : 
namespacePrefix,
+                            namespaceURI == null ? "" : namespaceURI);
+                }
+                break;
+            case XMLStreamConstants.END_ELEMENT:
+                writer.writeEndElement();
+                break;
+            case XMLStreamConstants.CHARACTERS:
+                writer.writeCharacters(reader.getText());
+                break;
+            case XMLStreamConstants.COMMENT:
+                writer.writeComment(reader.getText());
+                break;
+            case XMLStreamConstants.CDATA:
+                writer.writeCData(reader.getText());
+                break;
+            default:
+                break;
+        }
+    }
+
     static class TrimmableCharArrayWriter extends CharArrayWriter {
         public void trim(int head, int tail) {
             System.arraycopy(buf, head, buf, 0, count - head - tail);
diff --git 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/util/xml/XmlLineNumberParser.java
 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/util/xml/XmlLineNumberParser.java
index 813c881ad27f..8cbb1526c717 100644
--- 
a/core/camel-xml-jaxp/src/main/java/org/apache/camel/util/xml/XmlLineNumberParser.java
+++ 
b/core/camel-xml-jaxp/src/main/java/org/apache/camel/util/xml/XmlLineNumberParser.java
@@ -146,6 +146,7 @@ public final class XmlLineNumberParser {
         final DefaultHandler handler = new DefaultHandler() {
             private Locator locator;
             private boolean found;
+            private boolean done;
 
             @Override
             public void setDocumentLocator(final Locator locator) {
@@ -167,6 +168,10 @@ public final class XmlLineNumberParser {
                     throws SAXException {
                 addTextIfNeeded();
 
+                if (done) {
+                    // only the first root element is parsed (there can only 
be one document element)
+                    return;
+                }
                 if (rootNames != null && !found) {
                     if (isRootName(qName)) {
                         found = true;
@@ -205,6 +210,11 @@ public final class XmlLineNumberParser {
                     if (elementStack.isEmpty()) {
                         // Is this the root element?
                         doc.appendChild(closedEl);
+                        if (rootNames != null) {
+                            // the root element is done, so elements after it 
are not parsed
+                            found = false;
+                            done = true;
+                        }
                     } else {
                         final Element parentEl = elementStack.peek();
                         parentEl.appendChild(closedEl);
@@ -237,8 +247,9 @@ public final class XmlLineNumberParser {
                     if (el != null) {
                         final Node textNode = 
doc.createTextNode(textBuffer.toString());
                         el.appendChild(textNode);
-                        textBuffer.delete(0, textBuffer.length());
                     }
+                    // text outside the elements that are parsed is not added 
to the next element
+                    textBuffer.delete(0, textBuffer.length());
                 }
             }
         };

Reply via email to