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/09/11 10:53:35 UTC
git commit: CAMEL-7801 XMLTokenizer's wrapped mode to handle grouping
without replicating the wrapper part
Repository: camel
Updated Branches:
refs/heads/master a5dbf6688 -> 2c01b8e84
CAMEL-7801 XMLTokenizer's wrapped mode to handle grouping without replicating the wrapper part
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/2c01b8e8
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/2c01b8e8
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/2c01b8e8
Branch: refs/heads/master
Commit: 2c01b8e843e4a3d2eecce452470fba02a46ca790
Parents: a5dbf66
Author: Akitoshi Yoshida <ay...@apache.org>
Authored: Wed Sep 10 18:09:48 2014 +0200
Committer: Akitoshi Yoshida <ay...@apache.org>
Committed: Thu Sep 11 10:52:37 2014 +0200
----------------------------------------------------------------------
.../apache/camel/builder/ExpressionBuilder.java | 6 +
.../language/tokenizer/XMLTokenizeLanguage.java | 7 -
.../model/language/XMLTokenizerExpression.java | 14 +-
.../support/XMLTokenExpressionIterator.java | 95 ++++-
.../XMLTokenizeLanguageGroupingTest.java | 141 +++++++
.../XMLTokenizeWrapLanguageGroupingTest.java | 148 +++++++
.../processor/SplitGroupMultiXmlTokenTest.java | 6 +-
.../SplitGroupWrappedMultiXmlTokenTest.java | 81 ++++
.../XMLTokenExpressionIteratorGroupingTest.java | 415 +++++++++++++++++++
9 files changed, 887 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
index dfb4b99..4473fe7 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
@@ -1259,6 +1259,12 @@ public final class ExpressionBuilder {
return new XMLTokenExpressionIterator(path, mode);
}
+
+ public static Expression tokenizeXMLAwareExpression(String path, char mode, int group) {
+ ObjectHelper.notEmpty(path, "path");
+
+ return new XMLTokenExpressionIterator(path, mode, group);
+ }
/**
* Returns a tokenize expression which will tokenize the string with the
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/main/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguage.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguage.java b/camel-core/src/main/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguage.java
index 2b38128..b42357f 100644
--- a/camel-core/src/main/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguage.java
+++ b/camel-core/src/main/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguage.java
@@ -74,13 +74,6 @@ public class XMLTokenizeLanguage extends LanguageSupport {
ObjectHelper.notNull(path, "token");
Expression answer = ExpressionBuilder.tokenizeXMLAwareExpression(path, mode);
-
- // if group then wrap answer in group expression
- if (group > 0) {
- //REVISIT wrap the xml tokens with a group element to turn the result into xml?
- answer = ExpressionBuilder.groupIteratorExpression(answer, null, group);
- }
-
return answer;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java b/camel-core/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java
index 8e96044..323024a 100644
--- a/camel-core/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java
+++ b/camel-core/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java
@@ -87,6 +87,9 @@ public class XMLTokenizerExpression extends NamespaceAwareExpression {
if (mode != null) {
setProperty(expression, "mode", mode);
}
+ if (group != null) {
+ setProperty(expression, "group", group);
+ }
}
@Override
@@ -98,17 +101,14 @@ public class XMLTokenizerExpression extends NamespaceAwareExpression {
if (mode != null) {
setProperty(predicate, "mode", mode);
}
+ if (group != null) {
+ setProperty(predicate, "group", group);
+ }
}
@Override
public Expression createExpression(CamelContext camelContext) {
- Expression answer = super.createExpression(camelContext);
- if (group != null) {
- if (group > 0) {
- //REVISIT wrap the xml tokens with a group element to turn the result into xml?
- answer = ExpressionBuilder.groupIteratorExpression(answer, null, group);
- }
- }
+ Expression answer = super.createExpression(camelContext);
return answer;
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/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 d48a2d4..f233281 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
@@ -53,12 +53,18 @@ import org.slf4j.LoggerFactory;
public class XMLTokenExpressionIterator extends ExpressionAdapter implements NamespaceAware {
protected final String path;
protected char mode;
+ protected int group;
protected Map<String, String> nsmap;
public XMLTokenExpressionIterator(String path, char mode) {
+ this(path, mode, 1);
+ }
+
+ public XMLTokenExpressionIterator(String path, char mode, int group) {
ObjectHelper.notEmpty(path, "path");
this.path = path;
this.mode = mode;
+ this.group = group > 1 ? group : 1;
}
@Override
@@ -74,6 +80,14 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
this.mode = mode != null ? mode.charAt(0) : 0;
}
+ public int getGroup() {
+ return group;
+ }
+
+ public void setGroup(int group) {
+ this.group = group;
+ }
+
protected Iterator<?> createIterator(InputStream in, String charset) throws XMLStreamException, UnsupportedEncodingException {
Reader reader;
if (charset == null) {
@@ -81,12 +95,12 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
} else {
reader = new InputStreamReader(in, charset);
}
- XMLTokenIterator iterator = new XMLTokenIterator(path, nsmap, mode, reader);
+ XMLTokenIterator iterator = new XMLTokenIterator(path, nsmap, mode, group, reader);
return iterator;
}
protected Iterator<?> createIterator(Reader in) throws XMLStreamException {
- XMLTokenIterator iterator = new XMLTokenIterator(path, nsmap, mode, in);
+ XMLTokenIterator iterator = new XMLTokenIterator(path, nsmap, mode, group, in);
return iterator;
}
@@ -147,12 +161,14 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
private AttributedQName[] splitpath;
private int index;
private char mode;
+ private int group;
private RecordableReader in;
private XMLStreamReader reader;
private List<QName> path;
private List<Map<String, String>> namespaces;
private List<String> segments;
private List<QName> segmentlog;
+ private List<String> tokens;
private int code;
private int consumed;
private boolean backtrack;
@@ -164,10 +180,20 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
public XMLTokenIterator(String path, Map<String, String> nsmap, char mode, InputStream in, String charset)
throws XMLStreamException, UnsupportedEncodingException {
// woodstox's getLocation().etCharOffset() does not return the offset correctly for InputStream, so use Reader instead.
+ this(path, nsmap, mode, 1, new InputStreamReader(in, charset));
+ }
+
+ public XMLTokenIterator(String path, Map<String, String> nsmap, char mode, int group, InputStream in, String charset)
+ throws XMLStreamException, UnsupportedEncodingException {
+ // woodstox's getLocation().etCharOffset() does not return the offset correctly for InputStream, so use Reader instead.
this(path, nsmap, mode, new InputStreamReader(in, charset));
}
public XMLTokenIterator(String path, Map<String, String> nsmap, char mode, Reader in) throws XMLStreamException {
+ this(path, nsmap, mode, 1, in);
+ }
+
+ public XMLTokenIterator(String path, Map<String, String> nsmap, char mode, int group, Reader in) throws XMLStreamException {
final String[] sl = path.substring(1).split("/");
this.splitpath = new AttributedQName[sl.length];
for (int i = 0; i < sl.length; i++) {
@@ -182,6 +208,7 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
}
this.mode = mode != 0 ? mode : 'i';
+ this.group = group > 0 ? group : 1;
this.in = new RecordableReader(in);
this.reader = new StaxConverter().createXMLStreamReader(this.in);
@@ -201,7 +228,10 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
} else if (this.mode == 'i') {
this.namespaces = new ArrayList<Map<String, String>>();
}
-
+ // when grouping the tokens, allocate the storage to temporarily store tokens.
+ if (this.group > 1) {
+ this.tokens = new ArrayList<String>();
+ }
this.nextToken = getNextToken();
}
@@ -336,7 +366,7 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
private String createContextualToken(String token) {
StringBuilder sb = new StringBuilder();
- if (mode == 'w') {
+ if (mode == 'w' && group == 1) {
for (int i = 0; i < segments.size(); i++) {
sb.append(segments.get(i));
}
@@ -389,17 +419,45 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
}
sb.append(token.substring(ep + 1, bp));
}
+ } else {
+ return token;
}
return sb.toString();
}
+ private String getGroupedToken() {
+ StringBuilder sb = new StringBuilder();
+ if (mode == 'w') {
+ // for wrapped
+ for (int i = 0; i < segments.size(); i++) {
+ sb.append(segments.get(i));
+ }
+ for (String s : tokens) {
+ sb.append(s);
+ }
+ for (int i = path.size() - 1; i >= 0; i--) {
+ QName q = path.get(i);
+ sb.append("</").append(makeName(q)).append(">");
+ }
+ } else {
+ // for injected, unwrapped, text
+ sb.append("<group>");
+ for (String s : tokens) {
+ sb.append(s);
+ }
+ sb.append("</group>");
+ }
+ tokens.clear();
+ return sb.toString();
+ }
+
private String getNextToken() throws XMLStreamException {
- int code = 0;
- while (code != XMLStreamConstants.END_DOCUMENT) {
- code = readNext();
+ int xcode = 0;
+ while (xcode != XMLStreamConstants.END_DOCUMENT) {
+ xcode = readNext();
- switch (code) {
+ switch (xcode) {
case XMLStreamConstants.START_ELEMENT:
depth++;
QName name = reader.getName();
@@ -424,7 +482,14 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
token = getCurrentToken();
backtrack = true;
trackdepth = depth;
- return token;
+ if (group > 1) {
+ tokens.add(token);
+ if (group == tokens.size()) {
+ return getGroupedToken();
+ }
+ } else {
+ return token;
+ }
} else {
// intermediary match
down();
@@ -437,6 +502,13 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
}
break;
case XMLStreamConstants.END_ELEMENT:
+ if ((backtrack || (trackdepth > 0 && depth == trackdepth))
+ && (mode == 'w' && group > 1 && tokens.size() > 0)) {
+ // flush the left over using the current context
+ code = XMLStreamConstants.END_ELEMENT;
+ return getGroupedToken();
+ }
+
depth--;
QName endname = reader.getName();
LOG.trace("ee={}", endname);
@@ -474,6 +546,11 @@ public class XMLTokenExpressionIterator extends ExpressionAdapter implements Nam
break;
case XMLStreamConstants.END_DOCUMENT:
LOG.trace("depth={}", depth);
+ if (group > 1 && tokens.size() > 0) {
+ // flush the left over before really going EoD
+ code = XMLStreamConstants.END_DOCUMENT;
+ return getGroupedToken();
+ }
break;
default:
break;
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguageGroupingTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguageGroupingTest.java b/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguageGroupingTest.java
new file mode 100644
index 0000000..79fd0df
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeLanguageGroupingTest.java
@@ -0,0 +1,141 @@
+/**
+ * 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.language.tokenizer;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.xml.Namespaces;
+import org.apache.camel.component.mock.MockEndpoint;
+
+public class XMLTokenizeLanguageGroupingTest extends ContextTestSupport {
+
+ public void testSendClosedTagMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("<group><c:child some_attr='a' anotherAttr='a' xmlns:c=\"urn:c\"></c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' xmlns:c=\"urn:c\"></c:child></group>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a'></c:child><c:child some_attr='b' anotherAttr='b'></c:child></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendClosedTagWithLineBreaksMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("<group><c:child some_attr='a' anotherAttr='a' xmlns:c=\"urn:c\">\n</c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' xmlns:c=\"urn:c\">\n</c:child></group>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ + "<c:parent xmlns:c='urn:c'>\n"
+ + "<c:child some_attr='a' anotherAttr='a'>\n"
+ + "</c:child>\n"
+ + "<c:child some_attr='b' anotherAttr='b'>\n"
+ + "</c:child>\n"
+ + "</c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendSelfClosingTagMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("<group><c:child some_attr='a' anotherAttr='a' xmlns:c=\"urn:c\"/>"
+ + "<c:child some_attr='b' anotherAttr='b' xmlns:c=\"urn:c\"/></group>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a' /><c:child some_attr='b' anotherAttr='b' /></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendMixedClosingTagMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<group><c:child some_attr='a' anotherAttr='a' xmlns:c=\"urn:c\">ha</c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' xmlns:c=\"urn:c\"/></group>",
+ "<group><c:child some_attr='c' xmlns:c=\"urn:c\"></c:child></group>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a'>ha</c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' /><c:child some_attr='c'></c:child></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendMixedClosingTagInsideMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<group><c:child name='child1' xmlns:c=\"urn:c\"><grandchild name='grandchild1'/> <grandchild name='grandchild2'/></c:child>"
+ + "<c:child name='child2' xmlns:c=\"urn:c\"><grandchild name='grandchild1'></grandchild><grandchild name='grandchild2'></grandchild></c:child></group>");
+
+ template.sendBody("direct:start",
+ "<c:parent xmlns:c='urn:c'><c:child name='child1'><grandchild name='grandchild1'/> <grandchild name='grandchild2'/></c:child>"
+ + "<c:child name='child2'><grandchild name='grandchild1'></grandchild><grandchild name='grandchild2'></grandchild></c:child></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendNamespacedChildMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<group><c:child xmlns:c='urn:c' some_attr='a' anotherAttr='a'></c:child><c:child xmlns:c='urn:c' some_attr='b' anotherAttr='b' /></group>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child xmlns:c='urn:c' some_attr='a' anotherAttr='a'></c:child>"
+ + "<c:child xmlns:c='urn:c' some_attr='b' anotherAttr='b' /></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendNamespacedParentMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<group><c:child some_attr='a' anotherAttr='a' xmlns:d=\"urn:d\" xmlns:c=\"urn:c\"></c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' xmlns:d=\"urn:d\" xmlns:c=\"urn:c\"/></group>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c' xmlns:d=\"urn:d\"><c:child some_attr='a' anotherAttr='a'></c:child>"
+ + "<c:child some_attr='b' anotherAttr='b'/></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendMoreParentsMessageToTokenize() throws Exception {
+ MockEndpoint result = getMockEndpoint("mock:result");
+ if (isJavaVersion("1.8")) {
+ result.expectedBodiesReceived(
+ "<group><c:child some_attr='a' anotherAttr='a' xmlns:c=\"urn:c\" xmlns:d=\"urn:d\" xmlns:g=\"urn:g\"></c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' xmlns:c=\"urn:c\" xmlns:d=\"urn:d\" xmlns:g=\"urn:g\"/></group>");
+ } else {
+ result.expectedBodiesReceived(
+ "<group><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\"/></group>");
+ }
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><g:greatgrandparent xmlns:g='urn:g'><grandparent><uncle/><aunt>emma</aunt><c:parent xmlns:c='urn:c' xmlns:d=\"urn:d\">"
+ + "<c:child some_attr='a' anotherAttr='a'></c:child><c:child some_attr='b' anotherAttr='b'/></c:parent></grandparent></g:greatgrandparent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ Namespaces ns = new Namespaces("C", "urn:c");
+ public void configure() {
+ from("direct:start")
+ .split().xtokenize("//C:child", 'i', ns, 2)
+ .to("mock:result")
+ .end();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeWrapLanguageGroupingTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeWrapLanguageGroupingTest.java b/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeWrapLanguageGroupingTest.java
new file mode 100644
index 0000000..728a70f
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/language/tokenizer/XMLTokenizeWrapLanguageGroupingTest.java
@@ -0,0 +1,148 @@
+/**
+ * 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.language.tokenizer;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.xml.Namespaces;
+
+public class XMLTokenizeWrapLanguageGroupingTest extends ContextTestSupport {
+
+ public void testSendClosedTagMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a'></c:child>"
+ + "<c:child some_attr='b' anotherAttr='b'></c:child></c:parent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a'></c:child><c:child some_attr='b' anotherAttr='b'></c:child></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendClosedTagWithLineBreaksMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("<?xml version='1.0' encoding='UTF-8'?>\n<c:parent xmlns:c='urn:c'>\n<c:child some_attr='a' anotherAttr='a'>\n</c:child>"
+ + "<c:child some_attr='b' anotherAttr='b'>\n</c:child></c:parent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?>\n"
+ + "<c:parent xmlns:c='urn:c'>\n"
+ + "<c:child some_attr='a' anotherAttr='a'>\n"
+ + "</c:child>\n"
+ + "<c:child some_attr='b' anotherAttr='b'>\n"
+ + "</c:child>\n"
+ + "</c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendSelfClosingTagMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived("<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a' />"
+ + "<c:child some_attr='b' anotherAttr='b' /></c:parent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a' /><c:child some_attr='b' anotherAttr='b' /></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendMixedClosingTagMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a'>ha</c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' /></c:parent>",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='c'></c:child></c:parent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child some_attr='a' anotherAttr='a'>ha</c:child>"
+ + "<c:child some_attr='b' anotherAttr='b' /><c:child some_attr='c'></c:child></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendMixedClosingTagInsideMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<c:parent xmlns:c='urn:c'><c:child name='child1'><grandchild name='grandchild1'/> <grandchild name='grandchild2'/></c:child>"
+ + "<c:child name='child2'><grandchild name='grandchild1'></grandchild><grandchild name='grandchild2'></grandchild></c:child></c:parent>");
+
+ template.sendBody("direct:start",
+ "<c:parent xmlns:c='urn:c'><c:child name='child1'><grandchild name='grandchild1'/> <grandchild name='grandchild2'/></c:child>"
+ + "<c:child name='child2'><grandchild name='grandchild1'></grandchild><grandchild name='grandchild2'></grandchild></c:child></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendNamespacedChildMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child xmlns:c='urn:c' some_attr='a' anotherAttr='a'></c:child>"
+ + "<c:child xmlns:c='urn:c' some_attr='b' anotherAttr='b' /></c:parent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c'><c:child xmlns:c='urn:c' some_attr='a' anotherAttr='a'></c:child>"
+ + "<c:child xmlns:c='urn:c' some_attr='b' anotherAttr='b' /></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendNamespacedParentMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c' xmlns:d=\"urn:d\"><c:child some_attr='a' anotherAttr='a'></c:child>"
+ + "<c:child some_attr='b' anotherAttr='b'/></c:parent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><c:parent xmlns:c='urn:c' xmlns:d=\"urn:d\"><c:child some_attr='a' anotherAttr='a'></c:child><c:child some_attr='b' anotherAttr='b'/></c:parent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendMoreParentsMessageToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<?xml version='1.0' encoding='UTF-8'?><g:greatgrandparent xmlns:g='urn:g'><grandparent><uncle/><aunt>emma</aunt><c:parent xmlns:c='urn:c' xmlns:d=\"urn:d\">"
+ + "<c:child some_attr='a' anotherAttr='a'></c:child>"
+ + "<c:child some_attr='b' anotherAttr='b'/></c:parent></grandparent></g:greatgrandparent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><g:greatgrandparent xmlns:g='urn:g'><grandparent><uncle/><aunt>emma</aunt><c:parent xmlns:c='urn:c' xmlns:d=\"urn:d\">"
+ + "<c:child some_attr='a' anotherAttr='a'></c:child><c:child some_attr='b' anotherAttr='b'/></c:parent></grandparent></g:greatgrandparent>");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ public void testSendParentMessagesWithDifferentAttributesToTokenize() throws Exception {
+ getMockEndpoint("mock:result").expectedBodiesReceived(
+ "<?xml version='1.0' encoding='UTF-8'?><g:grandparent xmlns:g='urn:g'><c:parent name='e' xmlns:c='urn:c' xmlns:d=\"urn:d\">"
+ + "<c:child some_attr='a' anotherAttr='a'></c:child></c:parent></g:grandparent>",
+ "<?xml version='1.0' encoding='UTF-8'?><g:grandparent xmlns:g='urn:g'><c:parent name='f' xmlns:c='urn:c' xmlns:d=\"urn:d\">"
+ + "<c:child some_attr='b' anotherAttr='b'/></c:parent></g:grandparent>");
+
+ template.sendBody("direct:start",
+ "<?xml version='1.0' encoding='UTF-8'?><g:grandparent xmlns:g='urn:g'><c:parent name='e' xmlns:c='urn:c' xmlns:d=\"urn:d\">"
+ + "<c:child some_attr='a' anotherAttr='a'></c:child></c:parent><c:parent name='f' xmlns:c='urn:c' xmlns:d=\"urn:d\"><c:child some_attr='b' anotherAttr='b'/>"
+ + "</c:parent></g:grandparent>");
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ Namespaces ns = new Namespaces("C", "urn:c");
+ public void configure() {
+ from("direct:start")
+ .split().xtokenize("//C:child", 'w', ns, 2)
+ .to("mock:result")
+ .end();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/test/java/org/apache/camel/processor/SplitGroupMultiXmlTokenTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/processor/SplitGroupMultiXmlTokenTest.java b/camel-core/src/test/java/org/apache/camel/processor/SplitGroupMultiXmlTokenTest.java
index 86f4201..67a1f90 100644
--- a/camel-core/src/test/java/org/apache/camel/processor/SplitGroupMultiXmlTokenTest.java
+++ b/camel-core/src/test/java/org/apache/camel/processor/SplitGroupMultiXmlTokenTest.java
@@ -36,9 +36,9 @@ public class SplitGroupMultiXmlTokenTest extends ContextTestSupport {
public void testTokenXMLPairGroup() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:split");
mock.expectedMessageCount(3);
- mock.message(0).body().isEqualTo("<order id=\"1\" xmlns=\"http:acme.com\">Camel in Action</order><order id=\"2\" xmlns=\"http:acme.com\">ActiveMQ in Action</order>");
- mock.message(1).body().isEqualTo("<order id=\"3\" xmlns=\"http:acme.com\">Spring in Action</order><order id=\"4\" xmlns=\"http:acme.com\">Scala in Action</order>");
- mock.message(2).body().isEqualTo("<order id=\"5\" xmlns=\"http:acme.com\">Groovy in Action</order>");
+ mock.message(0).body().isEqualTo("<group><order id=\"1\" xmlns=\"http:acme.com\">Camel in Action</order><order id=\"2\" xmlns=\"http:acme.com\">ActiveMQ in Action</order></group>");
+ mock.message(1).body().isEqualTo("<group><order id=\"3\" xmlns=\"http:acme.com\">Spring in Action</order><order id=\"4\" xmlns=\"http:acme.com\">Scala in Action</order></group>");
+ mock.message(2).body().isEqualTo("<group><order id=\"5\" xmlns=\"http:acme.com\">Groovy in Action</order></group>");
String body = createBody();
template.sendBodyAndHeader("file:target/pair", body, Exchange.FILE_NAME, "orders.xml");
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/test/java/org/apache/camel/processor/SplitGroupWrappedMultiXmlTokenTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/processor/SplitGroupWrappedMultiXmlTokenTest.java b/camel-core/src/test/java/org/apache/camel/processor/SplitGroupWrappedMultiXmlTokenTest.java
new file mode 100644
index 0000000..4c1fa94
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/processor/SplitGroupWrappedMultiXmlTokenTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.xml.Namespaces;
+import org.apache.camel.component.mock.MockEndpoint;
+
+/**
+ *
+ */
+public class SplitGroupWrappedMultiXmlTokenTest extends ContextTestSupport {
+
+ @Override
+ protected void setUp() throws Exception {
+ deleteDirectory("target/pair");
+ super.setUp();
+ }
+
+ public void testTokenXMLPairGroup() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:split");
+ mock.expectedMessageCount(3);
+ mock.message(0).body().isEqualTo(
+ "<?xml version=\"1.0\"?>\n<orders xmlns=\"http:acme.com\">\n <order id=\"1\">Camel in Action</order><order id=\"2\">ActiveMQ in Action</order></orders>");
+ mock.message(1).body().isEqualTo(
+ "<?xml version=\"1.0\"?>\n<orders xmlns=\"http:acme.com\">\n <order id=\"3\">Spring in Action</order><order id=\"4\">Scala in Action</order></orders>");
+ mock.message(2).body().isEqualTo(
+ "<?xml version=\"1.0\"?>\n<orders xmlns=\"http:acme.com\">\n <order id=\"5\">Groovy in Action</order></orders>");
+
+ String body = createBody();
+ template.sendBodyAndHeader("file:target/pair", body, Exchange.FILE_NAME, "orders.xml");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ protected String createBody() {
+ StringBuilder sb = new StringBuilder("<?xml version=\"1.0\"?>\n");
+ sb.append("<orders xmlns=\"http:acme.com\">\n");
+ sb.append(" <order id=\"1\">Camel in Action</order>\n");
+ sb.append(" <order id=\"2\">ActiveMQ in Action</order>\n");
+ sb.append(" <order id=\"3\">Spring in Action</order>\n");
+ sb.append(" <order id=\"4\">Scala in Action</order>\n");
+ sb.append(" <order id=\"5\">Groovy in Action</order>\n");
+ sb.append("</orders>");
+ return sb.toString();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ Namespaces ns = new Namespaces("", "http:acme.com");
+ @Override
+ public void configure() throws Exception {
+ // START SNIPPET: e1
+ from("file:target/pair")
+ // split the order child tags, and inherit namespaces from the orders root tag
+ .split().xtokenize("//order", 'w', ns, 2)
+ .to("log:split")
+ .to("mock:split");
+ // END SNIPPET: e1
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/2c01b8e8/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorGroupingTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorGroupingTest.java b/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorGroupingTest.java
new file mode 100644
index 0000000..20f5d45
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/support/XMLTokenExpressionIteratorGroupingTest.java
@@ -0,0 +1,415 @@
+/**
+ * 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.support;
+
+import java.io.ByteArrayInputStream;
+import java.io.Closeable;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ */
+public class XMLTokenExpressionIteratorGroupingTest extends TestCase {
+
+ private static final byte[] TEST_BODY = (
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "<c:C attr='2'/>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "<c:C attr='4'/>"
+ + "</c:B>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='5'>mango</c:C>"
+ + "<c:C attr='6'/>"
+ + "<c:C attr='7'>pear</c:C>"
+ + "<c:C attr='8'/>"
+ + "</c:B>"
+ + "</g:A>").getBytes();
+
+ private static final String[] RESULTS_WRAPPED_SIZE1 = {
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='2'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='4'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='5'>mango</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='6'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='7'>pear</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='8'/>"
+ + "</c:B>"
+ + "</g:A>"};
+
+ private static final String[] RESULTS_WRAPPED_SIZE2 = {
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "<c:C attr='2'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "<c:C attr='4'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='5'>mango</c:C>"
+ + "<c:C attr='6'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='7'>pear</c:C>"
+ + "<c:C attr='8'/>"
+ + "</c:B>"
+ + "</g:A>"};
+
+ private static final String[] RESULTS_WRAPPED_SIZE3L = {
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "<c:C attr='2'/>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='4'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='5'>mango</c:C>"
+ + "<c:C attr='6'/>"
+ + "<c:C attr='7'>pear</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='8'/>"
+ + "</c:B>"
+ + "</g:A>"};
+
+ private static final String[] RESULTS_WRAPPED_SIZE3U = {
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "<c:C attr='2'/>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='4'/>"
+ + "</c:B>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='5'>mango</c:C>"
+ + "<c:C attr='6'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='7'>pear</c:C>"
+ + "<c:C attr='8'/>"
+ + "</c:B>"
+ + "</g:A>"};
+
+ private static final String[] RESULTS_WRAPPED_SIZE4 = {
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "<c:C attr='2'/>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "<c:C attr='4'/>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='5'>mango</c:C>"
+ + "<c:C attr='6'/>"
+ + "<c:C attr='7'>pear</c:C>"
+ + "<c:C attr='8'/>"
+ + "</c:B>"
+ + "</g:A>"};
+
+ private static final String[] RESULTS_WRAPPED_SIZE5L = RESULTS_WRAPPED_SIZE4;
+
+ private static final String[] RESULTS_WRAPPED_SIZE5U = {
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "<c:C attr='2'/>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "<c:C attr='4'/>"
+ + "</c:B>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='5'>mango</c:C>"
+ + "</c:B>"
+ + "</g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<g:A xmlns:g='urn:g'>"
+ + "<c:B attr='2' xmlns:c='urn:c'>"
+ + "<c:C attr='6'/>"
+ + "<c:C attr='7'>pear</c:C>"
+ + "<c:C attr='8'/>"
+ + "</c:B>"
+ + "</g:A>"};
+
+ private static final String[] RESULTS_INJECTED_SIZE1 = {
+ "<c:C attr='1' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">peach</c:C>",
+ "<c:C attr='2' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>",
+ "<c:C attr='3' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">orange</c:C>",
+ "<c:C attr='4' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>",
+ "<c:C attr='5' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">mango</c:C>",
+ "<c:C attr='6' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>",
+ "<c:C attr='7' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">pear</c:C>",
+ "<c:C attr='8' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"};
+
+ private static final String[] RESULTS_INJECTED_SIZE2 = {
+ "<group>"
+ + "<c:C attr='1' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">peach</c:C>"
+ + "<c:C attr='2' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>",
+ "<group>"
+ + "<c:C attr='3' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">orange</c:C>"
+ + "<c:C attr='4' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>",
+ "<group>"
+ + "<c:C attr='5' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">mango</c:C>"
+ + "<c:C attr='6' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>",
+ "<group>"
+ + "<c:C attr='7' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">pear</c:C>"
+ + "<c:C attr='8' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>"};
+
+ private static final String[] RESULTS_INJECTED_SIZE3 = {
+ "<group>"
+ + "<c:C attr='1' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">peach</c:C>"
+ + "<c:C attr='2' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "<c:C attr='3' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">orange</c:C>"
+ + "</group>",
+ "<group>"
+ + "<c:C attr='4' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "<c:C attr='5' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">mango</c:C>"
+ + "<c:C attr='6' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>",
+ "<group>"
+ + "<c:C attr='7' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">pear</c:C>"
+ + "<c:C attr='8' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>"};
+
+ private static final String[] RESULTS_INJECTED_SIZE4 = {
+ "<group>"
+ + "<c:C attr='1' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">peach</c:C>"
+ + "<c:C attr='2' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "<c:C attr='3' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">orange</c:C>"
+ + "<c:C attr='4' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>",
+ "<group>"
+ + "<c:C attr='5' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">mango</c:C>"
+ + "<c:C attr='6' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "<c:C attr='7' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">pear</c:C>"
+ + "<c:C attr='8' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>"};
+
+ private static final String[] RESULTS_INJECTED_SIZE5 = {
+ "<group>"
+ + "<c:C attr='1' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">peach</c:C>"
+ + "<c:C attr='2' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "<c:C attr='3' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">orange</c:C>"
+ + "<c:C attr='4' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "<c:C attr='5' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">mango</c:C>"
+ + "</group>",
+ "<group>"
+ + "<c:C attr='6' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "<c:C attr='7' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\">pear</c:C>"
+ + "<c:C attr='8' xmlns:g=\"urn:g\" xmlns:c=\"urn:c\"/>"
+ + "</group>"};
+
+ private Map<String, String> nsmap;
+
+
+ @Override
+ public void setUp() {
+ nsmap = new HashMap<String, String>();
+ nsmap.put("g", "urn:g");
+ nsmap.put("c", "urn:c");
+ }
+
+ // wrapped mode
+ public void testExtractWrappedSize1() throws Exception {
+ invokeAndVerify("//c:C",
+ 'w', 1, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_WRAPPED_SIZE1);
+ }
+
+ public void testExtractWrappedSize2() throws Exception {
+ invokeAndVerify("//c:C",
+ 'w', 2, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_WRAPPED_SIZE2);
+ }
+
+ public void disabledtestExtractWrappedSize3L() throws Exception {
+ invokeAndVerify("//c:C",
+ 'w', 3, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_WRAPPED_SIZE3L);
+ }
+
+ // disabled: not working for now as the context extraction across two ancestor paths is not working
+ public void disabledtestExtractWrappedSize3U() throws Exception {
+ invokeAndVerify("//c:C",
+ 'W', 3, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_WRAPPED_SIZE3U);
+ }
+
+ public void testExtractWrappedSize4() throws Exception {
+ invokeAndVerify("//c:C",
+ 'w', 4, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_WRAPPED_SIZE4);
+ }
+
+ public void disabledtestExtractWrappedSize5L() throws Exception {
+ invokeAndVerify("//c:C",
+ 'w', 5, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_WRAPPED_SIZE5L);
+ }
+
+ // disabled: not working for now as the context extraction across two ancestor paths is not working
+ public void disabledtestExtractWrappedSize5U() throws Exception {
+ invokeAndVerify("//c:C",
+ 'W', 5, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_WRAPPED_SIZE5U);
+ }
+
+ // injected mode
+ public void testExtractInjectedSize1() throws Exception {
+ invokeAndVerify("//c:C",
+ 'i', 1, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_INJECTED_SIZE1);
+ }
+
+ public void testExtractInjectedSize2() throws Exception {
+ invokeAndVerify("//c:C",
+ 'i', 2, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_INJECTED_SIZE2);
+ }
+
+ public void testExtractInjectedSize3() throws Exception {
+ invokeAndVerify("//c:C",
+ 'i', 3, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_INJECTED_SIZE3);
+ }
+
+ public void testExtractInjectedSize4() throws Exception {
+ invokeAndVerify("//c:C",
+ 'i', 4, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_INJECTED_SIZE4);
+ }
+
+ public void testExtractInjectedSize5() throws Exception {
+ invokeAndVerify("//c:C",
+ 'i', 5, new ByteArrayInputStream(TEST_BODY), "utf-8", RESULTS_INJECTED_SIZE5);
+ }
+
+ public void testExtractWrappedLeftOver() throws Exception {
+ final byte[] data = ("<?xml version='1.0' encoding='UTF-8'?><g:A xmlns:g='urn:g'><c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C>"
+ + "<c:C attr='2'/>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "</c:B></g:A>").getBytes();
+ final String[] results = {"<?xml version='1.0' encoding='UTF-8'?><g:A xmlns:g='urn:g'><c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='1'>peach</c:C><c:C attr='2'/>"
+ + "</c:B></g:A>",
+ "<?xml version='1.0' encoding='UTF-8'?><g:A xmlns:g='urn:g'><c:B attr='1' xmlns:c='urn:c'>"
+ + "<c:C attr='3'>orange</c:C>"
+ + "</c:B></g:A>"};
+ invokeAndVerify("//c:C",
+ 'w', 2, new ByteArrayInputStream(data), "utf-8", results);
+ }
+
+ private void invokeAndVerify(String path, char mode, int group,
+ InputStream in, String charset, String[] expected)
+ throws Exception {
+ XMLTokenExpressionIterator xtei = new XMLTokenExpressionIterator(path, mode);
+ xtei.setNamespaces(nsmap);
+ xtei.setGroup(group);
+
+ Iterator<?> it = xtei.createIterator(in, "utf-8");
+ List<String> results = new ArrayList<String>();
+ while (it.hasNext()) {
+ results.add((String)it.next());
+ }
+ ((Closeable)it).close();
+
+ assertEquals("token count", expected.length, results.size());
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("mismatch [" + i + "]", expected[i], results.get(i));
+ }
+ }
+}