Search code examples
javaxpathjbossapache-cameljbossfuse

Not able to set header using XPATH


I have an scenario where I am splitting an xml and sending them to activemq and then want to log header orderid and region. For getting region I am using a java method:

        import org.apache.camel.language.NamespacePrefix;
        import org.apache.camel.language.XPath;

        /**
         * This class contains business logic that determines the region for a country. It is used by the Camel route in this example.
         */
        public class RegionSupport {

            public static final String AMER = "AMER";
            public static final String APAC = "APAC";
            public static final String EMEA = "EMEA";

            /**
             * Get the region code that corresponds to the given country code.
             * 
             * This method can be used as a plain Java method. However, when it is used inside a Camel route, the @XPath annotation will
             * evaluate the XPath expression and use the result as the method parameter. In this case, it will fetch the country code
             * from the order XML message. So, the method will determine the region code for the country that is in the XML message.
             * 
             * @param country the country code
             * @return the region code
             */
            public String getRegion(@XPath(value = "/order:order/order:customer/order:country",


     String country) {
                if (country.equals("AU")) {
                    return APAC;
                } else if (country.equals("US")) {
                    return AMER;
                } else {
                    return EMEA;
                }
            }
        }

XML INPUT :

So as per below xml I should log header as id =2012_0001 Region = APAC in first Exchange

<?xml version="1.0" encoding="UTF-8"?>
<orders>
    <order id="2012_0001">

        <customer id="A0001">
            <name>Antwerp Zoo</name>
            <city>Antwerp</city>
            <country>AU</country>
        </customer>

        <date>2012-03-01</date>

        <orderlines>
            <orderline>
                <article id="A0001">
                    <description>Aardvark</description>
                </article>
                <quantity>1</quantity>
            </orderline>
            <orderline>
                <article id="A0011">
                    <description>Alpaca</description>
                </article>
                <quantity>10</quantity>
            </orderline>
        </orderlines>
    </order>
    <order id="2012_0002">

        <customer id="B0002">
            <name>Bristol Zoo Gardens</name>
            <city>Bristol</city>
            <country>UK</country>
        </customer>

        <date>2012-03-02</date>

        <orderlines>
            <orderline>
                <article id="B0002">
                    <description>Badger</description>
                </article>
                <quantity>2</quantity>
            </orderline>
            <orderline>
                <article id="B0202">
                    <description>Bee</description>
                </article>
                <quantity>200</quantity>
            </orderline>
        </orderlines>
    </order>
    </orders>

XSLT :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="no" indent="yes"/>
    <xsl:template match="/">
        <xsl:element name="orders">
            <xsl:element name="order">
                <xsl:copy-of select="/*[local-name()='order']/*"
                />
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

my camel Route :

<route id="Splitter_Route">
            <from id="_from2" uri="direct:Splitter"/>
            <log id="_log6" message="Recieved file to split  : ${file:name}"/>
            <split id="_split1">
                <xpath>/orders/order</xpath>
                <log id="_log3" message="split data :  ${body}"/>
                <to id="_to1" uri="xslt:file:F:\jboss_workspace\ZooPattern\data\order.xsl"/>
                <log id="_log2" message="After XSLT : ${body} "/>
                <to id="_to2" uri="activemq:queue:zoodata"/>
                <log id="_log7" message="${body}"/>
                <setHeader headerName="orderId" id="_setHeader1">
                    <xpath resultType="java.lang.String">/order:order/@id</xpath>
                </setHeader>
                <setHeader headerName="region" id="_setHeader2">
                    <method bean="MyRegionSupport" method="getRegion"/>
                </setHeader>
                <log id="_log9" message="[splitter] Shipping order ${header.orderId}"/>
            </split>
        </route>

ERROR_Output :

So I am getting correct output till activemq . after the Activemq logid7 is not giving order id in xml . and after that it gives error as below . please let me know where I went wrong.

    thread #2 - file://zoodata/in] Splitter_Route                 INFO  split data :  <order id="2012_0001">

            <customer id="A0001">
                <name>Antwerp Zoo</name>
                <city>Antwerp</city>
                <country>BE</country>
            </customer>

            <date>2012-03-01</date>

            <orderlines>
                <orderline>
                    <article id="A0001">
                        <description>Aardvark</description>
                    </article>
                    <quantity>1</quantity>
                </orderline>
                <orderline>
                    <article id="A0011">
                        <description>Alpaca</description>
                    </article>
                    <quantity>10</quantity>
                </orderline>
            </orderlines>
        </order>
    [ thread #2 - file://zoodata/in] Splitter_Route                 INFO  After XSLT : <?xml version="1.0" encoding="UTF-8"?><orders>
    <order>
    <customer id="A0001">
                <name>Antwerp Zoo</name>
                <city>Antwerp</city>
                <country>BE</country>
            </customer>
    <date>2012-03-01</date>
    <orderlines>
                <orderline>
                    <article id="A0001">
                        <description>Aardvark</description>
                    </article>
                    <quantity>1</quantity>
                </orderline>
                <orderline>
                    <article id="A0011">
                        <description>Alpaca</description>
                    </article>
                    <quantity>10</quantity>
                </orderline>
            </orderlines>
    </order>
    </orders>

    [ thread #2 - file://zoodata/in] Splitter_Route                 INFO  <?xml version="1.0" encoding="UTF-8"?><orders>
    <order>
    <customer id="A0001">
                <name>Antwerp Zoo</name>
                <city>Antwerp</city>
                <country>BE</country>
            </customer>
    <date>2012-03-01</date>
    <orderlines>
                <orderline>
                    <article id="A0001">
                        <description>Aardvark</description>
                    </article>
                    <quantity>1</quantity>
                </orderline>
                <orderline>
                    <article id="A0011">
                        <description>Alpaca</description>
                    </article>
                    <quantity>10</quantity>
                </orderline>
            </orderlines>
    </order>
    </orders>

[ thread #2 - file://zoodata/in] DefaultErrorHandler            ERROR Failed delivery for (MessageId: ID-LAPTOP-OO1BQC0T-63587-1514125730408-0-37 on ExchangeId: ID-LAPTOP-OO1BQC0T-63587-1514125730408-0-38). Exhausted after delivery attempt: 1 caught: org.apache.camel.builder.xml.InvalidXPathExpression: Invalid xpath: /order:order/@id. Reason: javax.xml.xpath.XPathExpressionException: com.sun.org.apache.xpath.internal.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: order

    Message History
    ---------------------------------------------------------------------------------------------------------------------------------------
    RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
    [_route1           ] [_route1           ] [file://zoodata/in                                                             ] [        82]
    [Splitter_Route    ] [_log3             ] [log                                                                           ] [         0]
    [Splitter_Route    ] [_to1              ] [xslt:file:F:\jboss_workspace\ZooPattern\data\order.xsl                        ] [        15]
    [Splitter_Route    ] [_log2             ] [log                                                                           ] [         0]
    [Splitter_Route    ] [_to2              ] [activemq:queue:zoodata                                                        ] [        67]
    [Splitter_Route    ] [_log7             ] [log                                                                           ] [         0]
    [Splitter_Route    ] [_setHeader1       ] [setHeader[orderId]                                                            ] [         0]

    Stacktrace
    ---------------------------------------------------------------------------------------------------------------------------------------
    org.apache.camel.builder.xml.InvalidXPathExpression: Invalid xpath: /order:order/@id. Reason: javax.xml.xpath.XPathExpressionException: com.sun.org.apache.xpath.internal.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: order
        at org.apache.camel.builder.xml.XPathBuilder.evaluateAs(XPathBuilder.java:769)
        at org.apache.camel.builder.xml.XPathBuilder.evaluate(XPathBuilder.java:750)
        at org.apache.camel.builder.xml.XPathBuilder.evaluate(XPathBuilder.java:165)
        at org.apache.camel.processor.SetHeaderProcessor.process(SetHeaderProcessor.java:52)

Solution

  • The errors says

    Prefix must resolve to a namespace: order
    

    Which means you must setup the order namespace which you do in the XML file with your <camelContext>. In there you add it as an attribute

    <camelContext .... xmlns:order="http://bla bla">
    

    Where the value is the unique uri of the namespace which typically is some web url.

    However your XML input does NOT use namespaces, and therefore your problem is that your xpath in the setHeader is using it. However you should remove that and use anonymous xpath, which ought to be a simple fix

    <xpath resultType="java.lang.String">/order:order/@id</xpath>
    

    Should be

    <xpath resultType="java.lang.String">/order/@id</xpath>
    

    eg the order: with the colon is a namespace prefix, so that should be removed.