You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2012/11/28 18:42:36 UTC

svn commit: r1414836 - in /camel/trunk/camel-core/src: main/java/org/apache/camel/support/TokenXMLPairExpressionIterator.java test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java

Author: davsclaus
Date: Wed Nov 28 17:42:35 2012
New Revision: 1414836

URL: http://svn.apache.org/viewvc?rev=1414836&view=rev
Log:
CAMEL-5826: Fixed issue with XML streaming tokenizer dealing with inheriting namespaces from parent tag. Thanks to Rich Newcomb for the patch.

Added:
    camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java   (with props)
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/support/TokenXMLPairExpressionIterator.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/support/TokenXMLPairExpressionIterator.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/support/TokenXMLPairExpressionIterator.java?rev=1414836&r1=1414835&r2=1414836&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/support/TokenXMLPairExpressionIterator.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/support/TokenXMLPairExpressionIterator.java Wed Nov 28 17:42:35 2012
@@ -41,6 +41,7 @@ public class TokenXMLPairExpressionItera
 
     private static final Pattern NAMESPACE_PATTERN = Pattern.compile("xmlns(:\\w+|)=\\\"(.*?)\\\"");
     private static final String SCAN_TOKEN_REGEX = "(\\s+.*?|)>";
+    private static final String SCAN_TOKEN_NS_PREFIX_REGEX = "(.{1,15}?:|)";
     protected final String inheritNamespaceToken;
 
     public TokenXMLPairExpressionIterator(String startToken, String endToken, String inheritNamespaceToken) {
@@ -81,15 +82,22 @@ public class TokenXMLPairExpressionItera
         XMLTokenPairIterator(String startToken, String endToken, String inheritNamespaceToken, InputStream in, String charset) {
             super(startToken, endToken, true, in, charset);
 
-            // remove any ending > as we need to support attributes on the tags, so we need to use a reg exp pattern
-            String token = startToken.substring(0, startToken.length() - 1) + SCAN_TOKEN_REGEX;
-            this.startTokenPattern = Pattern.compile(token);
-            this.scanEndToken = endToken.substring(0, endToken.length() - 1) + SCAN_TOKEN_REGEX;
+            // remove any beginning < and ending > as we need to support ns prefixes and attributes, so we use a reg exp patterns
+            StringBuilder tokenSb = new StringBuilder("<").append(SCAN_TOKEN_NS_PREFIX_REGEX).
+                                append(startToken.substring(1, startToken.length() - 1)).append(SCAN_TOKEN_REGEX);
+            this.startTokenPattern = Pattern.compile(tokenSb.toString());
+            
+            tokenSb = new StringBuilder("</").append(SCAN_TOKEN_NS_PREFIX_REGEX).
+                                append(endToken.substring(2, endToken.length() - 1)).append(SCAN_TOKEN_REGEX);
+            this.scanEndToken = tokenSb.toString();
+            
             this.inheritNamespaceToken = inheritNamespaceToken;
             if (inheritNamespaceToken != null) {
-                token = inheritNamespaceToken.substring(0, inheritNamespaceToken.length() - 1) + SCAN_TOKEN_REGEX;
+                // the inherit namespace token may itself have a namespace prefix
+                tokenSb = new StringBuilder("<").append(SCAN_TOKEN_NS_PREFIX_REGEX).
+                                append(inheritNamespaceToken.substring(1, inheritNamespaceToken.length() - 1)).append(SCAN_TOKEN_REGEX);  
                 // the namespaces on the parent tag can be in multi line, so we need to instruct the dot to support multilines
-                this.inheritNamespaceTokenPattern = Pattern.compile(token, Pattern.MULTILINE | Pattern.DOTALL);
+                this.inheritNamespaceTokenPattern = Pattern.compile(tokenSb.toString(), Pattern.MULTILINE | Pattern.DOTALL);
             }
         }
 
@@ -125,17 +133,26 @@ public class TokenXMLPairExpressionItera
                 next = next.substring(index);
             }
 
+            // make sure the end tag matches the begin tag if the tag has a namespace prefix
+            String tag = ObjectHelper.before(next, ">");
+            StringBuilder endTagSb = new StringBuilder("</");
+            int firstSpaceIndex = tag.indexOf(" ");
+            if (firstSpaceIndex > 0) {
+                endTagSb.append(tag.substring(1, firstSpaceIndex)).append(">");
+            } else {
+                endTagSb.append(tag.substring(1, tag.length())).append(">");
+            }
+            
             // build answer accordingly to whether namespaces should be inherited or not
             StringBuilder sb = new StringBuilder();
             if (inheritNamespaceToken != null && rootTokenNamespaces != null) {
                 // append root namespaces to local start token
-                String tag = ObjectHelper.before(next, ">");
                 // grab the text
                 String text = ObjectHelper.after(next, ">");
                 // build result with inherited namespaces
-                next = sb.append(tag).append(rootTokenNamespaces).append(">").append(text).append(endToken).toString();
+                next = sb.append(tag).append(rootTokenNamespaces).append(">").append(text).append(endTagSb.toString()).toString();
             } else {
-                next = sb.append(next).append(endToken).toString();
+                next = sb.append(next).append(endTagSb.toString()).toString();
             }
 
             return next;

Added: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java?rev=1414836&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java Wed Nov 28 17:42:35 2012
@@ -0,0 +1,84 @@
+/**
+ * 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.processor;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+
+public class SplitTokenizerNamespaceTest extends ContextTestSupport {
+
+    public void testSplitTokenizerWithImplicitNamespaces() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:split");
+        
+        // we expect to receive results that have namespace definitions on each token
+        // we could receive nodes from multiple namespaces since we did not specify a namespace prefix, 
+        mock.expectedBodiesReceived(
+            "<ns1:person xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">Claus</ns1:person>", 
+            "<ns1:person xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">James</ns1:person>", 
+            "<ns1:person xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">Willem</ns1:person>",
+            "<ns2:person xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">Rich</ns2:person>");
+
+        template.sendBody("direct:noPrefix", getXmlBody());
+
+        assertMockEndpointsSatisfied();
+    }
+
+    public void testSplitTokenizerWithExplicitNamespaces() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:split");
+        
+        // we expect to receive results that have namespace definitions on each token
+        // we provided an explicit namespace prefix value in the route, so we will only receive nodes that have a matching prefix value
+        mock.expectedBodiesReceived(
+            "<ns1:person xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">Claus</ns1:person>", 
+            "<ns1:person xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">James</ns1:person>", 
+            "<ns1:person xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">Willem</ns1:person>");
+
+        template.sendBody("direct:explicitPrefix", getXmlBody());
+
+        assertMockEndpointsSatisfied();
+    }
+
+    protected String getXmlBody() {
+        StringBuilder sb = new StringBuilder("<?xml version=\"1.0\"?>\n");
+        sb.append("<ns1:persons xmlns:ns1=\"urn:org.apache.camel\" xmlns:ns2=\"urn:org.apache.cameltoo\">\n");
+        sb.append("  <ns1:person>Claus</ns1:person>\n");
+        sb.append("  <ns1:person>James</ns1:person>\n");
+        sb.append("  <ns1:person>Willem</ns1:person>\n");
+        sb.append("  <ns2:person>Rich</ns2:person>\n");
+        sb.append("</ns1:persons>");
+        return sb.toString();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                
+                from("direct:noPrefix")
+                    .split().tokenizeXML("person", "persons")
+                    .to("mock:split");
+                
+                from("direct:explicitPrefix")
+                    .split().tokenizeXML("ns1:person", "ns1:persons")
+                    .to("mock:split");
+            }
+        };
+    }
+
+}
\ No newline at end of file

Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerNamespaceTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date