On 8/31/07, Neil Thorne <[EMAIL PROTECTED]> wrote:
>
> Hi I've got a test case here where I can't figure out how to use the
> XPathBuilder to create Splitter Expressions.
>
> I've got two tests in here. One suceeds. That's my custom splitter. It's all
> pure Java and suits my needs but I just spent so long on this XPath version
> it's just bugging me now.
>
> You can see my expectations in the test but in summary -
>
> For an xml snippet:
>
> <a><b>Ginger</b><b>Mr Boots</b></a>
>
>
> If I apply the xpath expression "a/b" in a splitter I expect to get a list
> of two Strings
>
> <b>Ginger</b>
> <b>Mr Boots</b>
>
> but I only ever see the String 'Ginger' arrive at the destination endpoint.
>
> What am I going wrong? Does the XPath expression just dump all the xml tags?
> And why am I only getting one result?
>
> And for a long time I was getting a test failure for the first case also. It
> might be that I'm trying to run jdk1.6 with IntelliJ 4.5. Anyways the
> problem was with the
> org.apache.camel.converter.ObjectConverter.iterator(Object value) method.
>
> I needed to change the camel code to explicitly cast the value to an
> Object[] when passing an array otherwise I was getting a list of size 1 with
> an Object[] in it, rather than a list of size Object[].length.
>
> eg.
>
> public static Iterator iterator(Object value) {
> if (value == null) {
> return Collections.EMPTY_LIST.iterator();
> } else if (value instanceof Collection) {
> Collection collection = (Collection)value;
> return collection.iterator();
> } else if (value.getClass().isArray()) {
> // TODO we should handle primitive array types?
> return Arrays.asList([Object]value).iterator();//see the
> explicit cast?
> } else {
> return Collections.singletonList(value).iterator();
> }
> }
>
> Weird? I made the change once but then I was able to remove the change again
> so probably just an IntelliJ-ism.
>
> See if the first test runs for you first time ;)
>
> Here's my test case
>
> package org.apache.camel.processor;
>
> import org.apache.camel.*;
> import org.apache.camel.builder.RouteBuilder;
> import org.apache.camel.builder.xml.XPathBuilder;
> import org.apache.camel.component.mock.MockEndpoint;
>
> public class NeilSplitterTest extends ContextTestSupport {
> protected Endpoint<Exchange> startEndpoint;
> protected MockEndpoint resultEndpoint;
>
> class CatFight {
>
> String name;
> String[] cats;
>
> public String[] getCats() {
> return cats;
> }
>
> public void setCats(String[] cats) {
> this.cats = cats;
> }
>
> public String getName() {
> return name;
> }
>
> public void setName(String name) {
> this.name = name;
> }
>
> }
>
> public void testCustomExpression() throws Exception {
>
> resultEndpoint.expectedBodiesReceived("Ginger", "Mr Boots");
>
> template.send("direct:custom", new Processor() {
> public void process(Exchange exchange) {
> Message in = exchange.getIn();
> CatFight catFight = new CatFight();
> catFight.setName("blueydart");
> catFight.setCats(new String[]{"Ginger", "Mr Boots"});
> in.setBody(catFight);
> in.setHeader("foo", "bar");
> }
> });
>
> resultEndpoint.assertIsSatisfied();
> }
>
> public void testXPathExpression() throws Exception {
>
> resultEndpoint.expectedBodiesReceived("<b>Ginger</b>",
> "<b>Mr Boots</b>");
>
> template.send("direct:xpath", new Processor() {
> public void process(Exchange exchange) {
> Message in = exchange.getIn();
> in.setBody("<a><b>Ginger</b><b>Mr
> Boots</b></a>");
> in.setHeader("foo", "bar");
> }
> });
>
> resultEndpoint.assertIsSatisfied();
> }
>
> @Override
> protected void setUp() throws Exception {
> super.setUp();
>
> resultEndpoint = (MockEndpoint)
> resolveMandatoryEndpoint("mock:result");
> }
>
> protected RouteBuilder createRouteBuilder() {
> return new RouteBuilder() {
> public void configure() {
> Expression catFightCats = new Expression(){
> public Object evaluate(Exchange exchange) {
> CatFight catFight = (CatFight)
> exchange.getIn().getBody();
> String[] cats = catFight.getCats();
> return cats;
> }
> };
>
> from("direct:custom").splitter(catFightCats).to("mock:result");
> XPathBuilder xPathBuilder = new XPathBuilder("a/b");
>
> from("direct:xpath").splitter(xPathBuilder).to("mock:result");
> }
> };
> }
> }
Firstly thanks for this awesome patch!
It turned up numerous problems. Firstly array expressions were not
being iterated over by default in the splitter (which I've now fixed).
Secondly JAXP is kinda wierd; by default if you don't specify an
explicit result type, the "a/b" evaluates to the string value of the
first node found! Truly strange.
So I've defaulted the type of XPath expressions to be NODESET, which
basically returns the correct XML fragment (so it splits into <b>
documents now). I did feel a bit dirty making this change; as any
string type XPath expression will barf now unless you explicitly call
the XPathBuilder.stringResult - e.g.
XPathBuilder.xpath("concat('hey', /foo.bar)").stringResult()
but I don't see a better way around this as yet. Anyone else any better ideas?
I've just commit your patch - see the NeilSplitterTest in the
camel.issues package. Thanks again!
--
James
-------
http://macstrac.blogspot.com/