You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ay...@apache.org on 2014/06/02 10:36:13 UTC

[2/2] git commit: add wildcard handling and fix the default nsdecl handling for the injected mode for CAMEL-7468

add wildcard handling and fix the default nsdecl handling for the injected mode for CAMEL-7468


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/22721385
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/22721385
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/22721385

Branch: refs/heads/master
Commit: 22721385334aace46c3b9943a1d715024c17ff73
Parents: f17f778
Author: Akitoshi Yoshida <ay...@apache.org>
Authored: Fri May 30 18:32:34 2014 +0200
Committer: Akitoshi Yoshida <ay...@apache.org>
Committed: Mon Jun 2 10:19:31 2014 +0200

----------------------------------------------------------------------
 .../support/TokenXMLExpressionIterator.java     |  3 -
 .../support/XMLTokenExpressionIterator.java     | 68 ++++++++++++++++----
 .../support/XMLTokenExpressionIteratorTest.java | 63 +++++++++++++++++-
 3 files changed, 116 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/22721385/camel-core/src/main/java/org/apache/camel/support/TokenXMLExpressionIterator.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/support/TokenXMLExpressionIterator.java b/camel-core/src/main/java/org/apache/camel/support/TokenXMLExpressionIterator.java
index 4192acf..497e63f 100644
--- a/camel-core/src/main/java/org/apache/camel/support/TokenXMLExpressionIterator.java
+++ b/camel-core/src/main/java/org/apache/camel/support/TokenXMLExpressionIterator.java
@@ -16,12 +16,9 @@
  */
 package org.apache.camel.support;
 
-import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
-import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Iterator;

http://git-wip-us.apache.org/repos/asf/camel/blob/22721385/camel-core/src/main/java/org/apache/camel/support/XMLTokenExpressionIterator.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/support/XMLTokenExpressionIterator.java b/camel-core/src/main/java/org/apache/camel/support/XMLTokenExpressionIterator.java
index 111bdaa..a8b8aa8 100644
--- a/camel-core/src/main/java/org/apache/camel/support/XMLTokenExpressionIterator.java
+++ b/camel-core/src/main/java/org/apache/camel/support/XMLTokenExpressionIterator.java
@@ -119,7 +119,7 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
         private static final Logger LOG = LoggerFactory.getLogger(XMLTokenIterator.class);
         private static final Pattern NAMESPACE_PATTERN = Pattern.compile("xmlns(:\\w+|)\\s*=\\s*('[^']+'|\"[^\"]+\")");
 
-        private QName[] splitpath;
+        private AttributedQName[] splitpath;
         private int index;
         private boolean wrap;
         private RecordableInputStream in;
@@ -138,13 +138,15 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
         
         public XMLTokenIterator(String path, Map<String, String> nsmap, boolean wrap, InputStream in, Exchange exchange) throws XMLStreamException {
             final String[] sl = path.substring(1).split("/");
-            this.splitpath = new QName[sl.length];
+            this.splitpath = new AttributedQName[sl.length];
             for (int i = 0; i < sl.length; i++) {
                 String s = sl[i];
                 if (s.length() > 0) {
                     int d = s.indexOf(':');
                     String pfx = d > 0 ? s.substring(0, d) : "";
-                    this.splitpath[i] = new QName(nsmap.get(pfx), d > 0 ? s.substring(d + 1) : s, pfx);
+                    this.splitpath[i] = 
+                        new AttributedQName(
+                            "*".equals(pfx) ? "*" : nsmap.get(pfx), d > 0 ? s.substring(d + 1) : s, pfx);
                 }
             }
             
@@ -154,7 +156,8 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
             this.reader = new StaxConverter().createXMLStreamReader(this.in, exchange);
 
             LOG.trace("reader.class: {}", reader.getClass());
-            if (reader.getLocation().getCharacterOffset() < 0) {
+            int coff = reader.getLocation().getCharacterOffset();
+            if (coff != 0) {
                 LOG.error("XMLStreamReader {} not supporting Location");
                 throw new XMLStreamException("reader not supporting Location");
             }
@@ -177,11 +180,11 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
             return splitpath[index] == null;
         }
         
-        private QName current() {
+        private AttributedQName current() {
             return splitpath[index + (isDoS() ? 1 : 0)];
         }
         
-        private QName ancestor() {
+        private AttributedQName ancestor() {
             return index == 0 ? null : splitpath[index - 1];
         }
 
@@ -335,7 +338,8 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
                 sb.append(token.substring(0, stag.length() - (empty ? 2 : 1)));
                 for (Entry<String, String> e : getCurrentNamespaceBindings().entrySet()) {
                     if (!skip.contains(e.getKey())) {
-                        sb.append(" xmlns:").append(e.getKey()).append("=").append(quote).append(e.getValue()).append(quote);
+                        sb.append(e.getKey().length() == 0 ? " xmlns" : " xmlns:")
+                            .append(e.getKey()).append("=").append(quote).append(e.getValue()).append(quote);
                     }
                 }
                 sb.append(token.substring(stag.length() - (empty ? 2 : 1)));
@@ -367,7 +371,7 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
                         pushNamespaces(reader);
                     }
                     backtrack = false;
-                    if (matches(name, current())) {
+                    if (current().matches(name)) {
                         // mark the position of the match in the segments list
                         if (isBottom()) {
                             // final match
@@ -417,7 +421,7 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
                         }
 
                         if ((ancestor() == null && !isTop())
-                            || (ancestor() != null && matches(endname, ancestor()))) {
+                            || (ancestor() != null && ancestor().matches(endname))) {
                             up();
                         }
                     }
@@ -437,10 +441,6 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
             return pfx.length() == 0 ? qname.getLocalPart() : qname.getPrefix() + ":" + qname.getLocalPart();
         }
 
-        private static boolean matches(QName a, QName b) {
-            return a.getNamespaceURI().equals(b.getNamespaceURI()) && a.getLocalPart().equals(b.getLocalPart());
-        }
-
         @Override
         public boolean hasNext() {
             return nextToken != null;
@@ -472,4 +472,46 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
         }
     }
 
+    static class AttributedQName extends QName {
+        private static final long serialVersionUID = 9878370226894144L;
+        private Pattern lcpattern;
+        private boolean nsany;
+        
+        public AttributedQName(String localPart) {
+            super(localPart);
+            checkWildcard("", localPart);
+        }
+
+        public AttributedQName(String namespaceURI, String localPart, String prefix) {
+            super(namespaceURI, localPart, prefix);
+            checkWildcard(namespaceURI, localPart);
+        }
+
+        public AttributedQName(String namespaceURI, String localPart) {
+            super(namespaceURI, localPart);
+            checkWildcard(namespaceURI, localPart);
+        }
+
+        public boolean matches(QName qname) {
+            return (nsany || getNamespaceURI().equals(qname.getNamespaceURI()))
+                && (lcpattern != null 
+                ? lcpattern.matcher(qname.getLocalPart()).matches() 
+                : getLocalPart().equals(qname.getLocalPart()));
+        }
+        
+        private void checkWildcard(String nsa, String lcp) {
+            nsany = "*".equals(nsa);
+            boolean wc = false;
+            for (int i = 0; i < lcp.length(); i++) {
+                char c = lcp.charAt(i);
+                if (c == '?' || c == '*') {
+                    wc = true;
+                    break;
+                }
+            }
+            if (wc) {
+                lcpattern = Pattern.compile(lcp.replace(".", "\\.").replace("*", ".*").replace("?", "."));
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/22721385/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorTest.java b/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorTest.java
index 67bb159..fe0c8bf 100644
--- a/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorTest.java
+++ b/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorTest.java
@@ -55,7 +55,21 @@ public class XMLTokenExpressionIteratorTest extends TestCase {
             + "</c:parent>"
             + "</grandparent>"
             + "</g:greatgrandparent>").getBytes();
-    
+
+    private static final byte[] TEST_BODY_NS_MIXED =
+        ("<?xml version='1.0' encoding='UTF-8'?>"
+            + "<g:greatgrandparent xmlns:g='urn:g'><grandparent>"
+            + "<parent some_attr='1' xmlns:c='urn:c' xmlns=\"urn:c\">"
+            + "<child some_attr='a' anotherAttr='a'></child>"
+            + "<x:child xmlns:x='urn:c' some_attr='b' anotherAttr='b'/>"
+            + "</parent>"
+            + "<c:parent some_attr='2' xmlns:c='urn:c'>"
+            + "<child some_attr='c' anotherAttr='c' xmlns='urn:c'></child>"
+            + "<c:child some_attr='d' anotherAttr='d'/>"
+            + "</c:parent>"
+            + "</grandparent>"
+            + "</g:greatgrandparent>").getBytes();
+
     private static final String[] RESULTS_CHILD_WRAPPED = {
         "<?xml version='1.0' encoding='UTF-8'?>"
             + "<g:greatgrandparent xmlns:g='urn:g'><grandparent><uncle/><aunt>emma</aunt>"
@@ -89,6 +103,28 @@ public class XMLTokenExpressionIteratorTest extends TestCase {
             + "</c:parent></grandparent></g:greatgrandparent>"
     };
 
+    private static final String[] RESULTS_CHILD_MIXED = {
+        "<child some_attr='a' anotherAttr='a' xmlns=\"urn:c\" xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"></child>",
+        "<x:child xmlns:x='urn:c' some_attr='b' anotherAttr='b' xmlns='urn:c' xmlns:g='urn:g' xmlns:c='urn:c'/>",
+        "<child some_attr='c' anotherAttr='c' xmlns='urn:c' xmlns:g='urn:g' xmlns:c='urn:c'></child>",
+        "<c:child some_attr='d' anotherAttr='d' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+    };
+
+    private static final String[] RESULTS_CHILD_MIXED_WRAPPED = {
+        "<?xml version='1.0' encoding='UTF-8'?><g:greatgrandparent xmlns:g='urn:g'><grandparent>"
+            + "<parent some_attr='1' xmlns:c='urn:c' xmlns=\"urn:c\">"
+            + "<child some_attr='a' anotherAttr='a'></child></parent></grandparent></g:greatgrandparent>",
+        "<?xml version='1.0' encoding='UTF-8'?><g:greatgrandparent xmlns:g='urn:g'><grandparent>"
+            + "<parent some_attr='1' xmlns:c='urn:c' xmlns=\"urn:c\">"
+            + "<x:child xmlns:x='urn:c' some_attr='b' anotherAttr='b'/></parent></grandparent></g:greatgrandparent>",
+        "<?xml version='1.0' encoding='UTF-8'?><g:greatgrandparent xmlns:g='urn:g'><grandparent>"
+            + "<c:parent some_attr='2' xmlns:c='urn:c'>"
+            + "<child some_attr='c' anotherAttr='c' xmlns='urn:c'></child></c:parent></grandparent></g:greatgrandparent>",
+        "<?xml version='1.0' encoding='UTF-8'?><g:greatgrandparent xmlns:g='urn:g'><grandparent>"
+            + "<c:parent some_attr='2' xmlns:c='urn:c'>"
+            + "<c:child some_attr='d' anotherAttr='d'/></c:parent></grandparent></g:greatgrandparent>"
+    };
+
     private static final String[] RESULTS_CHILD = {
         "<c:child some_attr='a' anotherAttr='a' xmlns:g=\"urn:g\" xmlns:d=\"urn:d\" xmlns:c=\"urn:c\"></c:child>",
         "<c:child some_attr='b' anotherAttr='b' xmlns:g=\"urn:g\" xmlns:d=\"urn:d\" xmlns:c=\"urn:c\"/>",
@@ -147,7 +183,10 @@ public class XMLTokenExpressionIteratorTest extends TestCase {
         "<aunt xmlns:g=\"urn:g\">emma</aunt>",
         "<aunt xmlns:g=\"urn:g\"/>"
     };    
-    
+
+    private static final String[] RESULTS_NULL = {
+    };
+ 
 
     private Map<String, String> nsmap;
     private Exchange exchange;
@@ -170,6 +209,26 @@ public class XMLTokenExpressionIteratorTest extends TestCase {
         invokeAndVerify("//C:child", false, new ByteArrayInputStream(TEST_BODY), RESULTS_CHILD);
     }
 
+    public void testExtractChildNSMixed() throws Exception {
+        invokeAndVerify("//*:child", true, new ByteArrayInputStream(TEST_BODY_NS_MIXED), RESULTS_CHILD_MIXED_WRAPPED);
+    }
+
+    public void testExtractChildNSMixedInjected() throws Exception {
+        invokeAndVerify("//*:child", false, new ByteArrayInputStream(TEST_BODY_NS_MIXED), RESULTS_CHILD_MIXED);
+    }
+
+    public void testExtractAnyChild() throws Exception {
+        invokeAndVerify("//*:child", true, new ByteArrayInputStream(TEST_BODY), RESULTS_CHILD_WRAPPED);
+    }
+
+    public void testExtractCxxxd() throws Exception {
+        invokeAndVerify("//C:c*d", false, new ByteArrayInputStream(TEST_BODY), RESULTS_CHILD);
+    }
+
+    public void testExtractUnqualifiedChild() throws Exception {
+        invokeAndVerify("//child", true, new ByteArrayInputStream(TEST_BODY), RESULTS_NULL);
+    }
+
     public void testExtractChildWithAncestorGGPdGP() throws Exception {
         invokeAndVerify("/G:greatgrandparent/grandparent//C:child", 
                         true, new ByteArrayInputStream(TEST_BODY), RESULTS_CHILD_WRAPPED);