New to Camel, and I'm trying to parse a response error xml. Within the camel-context I need to determine if a specific value exists in the error file, and handle it differently than other errors.
The other errors use a series of when statements:
<when>
<xpath>/abc:ErrorResponse/abc:Error/abc:Message/.</xpath>
<setHeader headerName="RESPONSE_STRING">
<xpath resultType="java.lang.String">/abc:ErrorResponse/abc:Error/abc:Message/.</xpath>
</setHeader>
<setHeader headerName="MY_DATA_FIELD"><constant>Error</constant></setHeader>
<to uri="def:doErrorStuff" pattern="InOnly"/>
</when>
<when>
<xpath>/ghi:ErrorResponse/ghi:Error/ghi:Message/.</xpath>
<setHeader headerName="RESPONSE_STRING">
<xpath resultType="java.lang.String">/ghi:ErrorResponse/ghi:Error/ghi:Message/.</xpath>
</setHeader>
<setHeader headerName="MY_DATA_FIELD"><constant>Error</constant></setHeader>
<to uri="def:doErrorStuff" pattern="InOnly"/>
</when>
My error XML file has an outer error element with child "Code" element. I need to parse the value of the code element
UPDATE: HERE IS THE XML I AM PARSING
<ErrorResponse xmlns="http://myhost/location1/">
<Error>
<Type>reserved</Type>
<Code>TEXT_I_NEED_TO_PARSE_IN_WHEN_STATEMENT</Code>
</Error>
<RequestId>some_id</RequestId>
</ErrorResponse>
I used a combination of xpath and 'simple' to make the check. Like this:
<when>
<xpath>/ghi:ErrorResponse/ghi:Error/ghi:Message/.</xpath>
<when>
<simple>${in.body.code} == 'StringIAmSearchingFor'</simple>
<!-- Do Stuff --!>
</when>
</when>
However, I am not getting the response I expect.
1. Is there something wrong with this approach or the syntax?
2. Is there a way to combine the double when layout so they are and-ed together. Otherwise, if I add my "when" statement just ahead of the existing two, the existing "ghi" when statement will never get executed (the xpath statements match).
You are using xpath on your input suggesting that it's XML, then simple (${in.body.code}) which in that case also would be XML. Simple is used to traverse java bodies and not other formats such as XML. Stick to XPATH all the way - your code above can easily be implemented in xpath. Another way, of course, would be to unmarshal the XML into java objects using xstream or jaxb, then you can use only simple/OGNL/groovy or whatnot.
Since I recommend you to solve this very case with xpath alone, you can of course use the xpath and operator to and several xpath expressions together. All logic and power in camel choice/when reside in the expression language you are using (be it simple or xpath), so if you want to mix expression languages, you have to build up sort of a decision tree. That could actually be something good if you are trying to implement very complex routing logic. For a single special case - it's, IMHO, just messy.
Related
I am trying to make a validation of XML requests on missing or empty XML tags. I used this code
<filter description="Validate material" regex=".+"
source="//E1MARAM[not(MATNR)] | //E1MARAM/MATNR[not(text())]">
<then>
<log category="WARN">
<property name="/material"
value="validation-empty tag MATNR send back to SAP" />
</log>
<property name="HTTP_SC" scope="axis2" type="STRING"
value="500" />
<makefault version="soap11">
<code value="soap11Env:VersionMismatch" xmlns:soap11Env="http://schemas.xmlsoap.org/soap/envelope/" />
<reason value="Missing SAP parameter" />
<detail>MATNR</detail>
</makefault>
<respond />
</then>
</filter>
which beatifically checks the XML tag //E1MARAM/MATNR
My problem is that this works only when the tag is empty.
It seems like the Filter mediator with reqex .+ and xpath //E1MARAM[not(MATNR)] does not meet the condition and thus the check does not work
Any idea why? or perhaps another idea how to better validate in WSO2 ESB on missing XML tags or values without XSD? a XSD schema cannot be used, as the XML request does not have a fixed structure - typical for SAP iDoc
The easiest way is to check for an not empty string ''. This will resolve to false both when empty and when missing. Also, you do not have to use the regex to check, you can just use xpath. If you give the filter mediator an xpath expression it will resolve it as if checking a boolean.
<filter description="Validate material" xpath="not(//E1MARAM/MATNR!=''") >
This will return true if the element is either empty or does not exist. It will return false if there is a text value.
I have a complex camel route, which starts with an initialization route, which tries to set the headers with the info from the XML used as input.
I wonder how the route is not being able to parse the XML content, using XPath.
Before calling the route, I print the xml information in my java JUNIT, and it prints correctly, with all xml tags.
So I know the information is being sent as I am expecting.
But that route, which should set the headers using XPath, returns empty to any expression I try to use! I even used a XPath tool to assist me (https://codebeautify.org/Xpath-Tester), to check if was some xpath coding mistake, but I get the results I want from there.
So, let's suppose, I have an XML as:
<bic:Test>
<bic:context>
<bic:memberCode>GOOGLE</bic:memberCode>
</bic:context>
</bic:Test>
So, with the line below:
<setHeader headerName="myHeader">
<xpath resultType="java.lang.String">//<anyTag>/text()</xpath>
</setHeader>
or
<setHeader headerName="myHeader">
<xpath resultType="java.lang.String">//<anyTag></xpath>
</setHeader>
I will see the header with empty content.
I tried so many different things, that finally I decided to print the all the content, using an XPath expression as /.
It will print only the content ("GOOGLE"), not the tags.
Could you please assist me?
Thank you in advance!
This is probably a namespace related issue.
You have to define the bic namespace in the camel context and then use it in the xpath expression.
Have a look at the documentation in https://github.com/apache/camel/blob/master/camel-core/src/main/docs/xpath-language.adoc and particularly in the example of "Using XML configuration"
Also look at "Namespace auditing to aid debugging" for further information about debugging namespace related issues in camel.
I am expecting multiple operation in one request. I need to to loop the xml to to do the following using Apache camel route.
1) get the total opertions in request xml and put in variable.
2) get total number of expression using xpath on xml and put in list
3) loop with (total number of operation ) times to evaluate the expression
First step would be list nodeList = /tractscation/operations
<loop>
<constant>nodeLIst.length</xpath>
compare and execute operation
</loop>
Above lines are just psuedo code, i want anybody help me with exact code using camel Xpath and loop. .
I am new to xpath and camel. we are using camelxpath spring DSL
if you want to loop through each node matching the xpath and process it individually, then use camel-splitter EIP...
<route>
<from uri="direct:a"/>
<split>
<xpath>/transaction/operations</xpath>
<to uri="direct:b"/>
</split>
</route>
otherwise, there is a camel-loop EIP that can be used to execute the same process a variable number of times...but the splitter is generally used for parsing/looping type of operations
from("direct:c").loop().xpath("/hello/#times").to("mock:result");
I hope it helps you =D
Inside route
<to uri="direct:WSCall" />
<split strategyRef="groupExchangeAggregationStrategy">
<xpath>//response/operation</xpath>
</split>
Velocity template
<tag>
#foreach( $exchangeItem in ${body} )
${exchangeItem.in.body}
#end
</tag>
Include
<beans>
<bean id="groupExchangeAggregationStrategy" class="org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy" />
</beans>
I have a blueprint.xml in which I write some routes for an ESB.
I want to get values from an XML file passed into the route.
I want to then use these values to make up a dynamic property key name and call the properties file and get the matching property (all within the route). I want to avoid having to create a Java processor due to the overhead of instantiating this each time.
Essentially I want to do this:
<from uri="file:C:/myfilelocation?"/>
<to uri= {{<xpath>//company</xpath>+<xpath>//branch</xpath>}}/>
So in blueprint you call a property using {{}}
I am trying to place the xpath values as the property key inside of the property {{}} tags. In my properties file I have a mapping for each company/branch combination like so:
company1branch1=http://thiscompany.com
company2branch2=http://someothercompany.com
Any way to do this, e.g. some sort of escape characters?
The < to > is for static uris, if you want to use dynamic runtime computed uris, then you should use the recipient list EIP: http://camel.apache.org/recipient-list.html that allows to send a message to a recipient calculcated at runtime.
This is also describer in this FAQ: http://camel.apache.org/how-do-i-use-dynamic-uri-in-to.html
Though with the xpath, you would need to set them as headers first.
Something a like:
<setHeader headerName="company">
<xpath resultType="java.lang.String">/xxxx</xpath>
</setHeader>
...
<recipientList><simple>{{${header.company}${header.branch}}}</simple></recipientList>
Also the recipient list can send to 2+ destinations, the separator is by default comma. But you can configure that. See the links above.
while 'playing around' with Camel using Spring DSL, I came across the following problem. Suppose the expected message flow looks like this:
client sends HTTP POST message with XML body to CAMEL
CAMEL proxies HTTP POST message towards server, with the URI slightly adapted using
info from the received XML body (eg: use XPATH to filter out a certain parameter)
after CAMEL has received a reply, CAMEL sends HTTP PUT message towards server, using parameters out of the XML body received in 1
So something like:
<route>
<from uri="...">
<to uri="...">
<to uri="...">
</route>
Question: how do I store the parameters in Spring DSL in step 1, so that I can use them later in step 3 ?
So, I would like to extract XML parameters out of the XML body of the message received in step 1 and put them into variables, which I then later on can use to compose the message to be sent in step 3.
For extracting the parameters, I was thinking of using XPATH. That looks ok, but I just don't see how to put the output of the XPATH into a variable and then use that variable later on ... (syntax ??)
Note: as you can see, my development knowledge is rather limited ... sorry for that. But it would still be great if someone could help with this :).
you can set store data in the Exchange properties or message headers like this...
.setHeader("ID", XPathBuilder.xpath("/order/#id", String.class))
.setProperty("ID", XPathBuilder.xpath("/order/#id", String.class))
and then retrieve them in a bean/processor from the Exchange like this...
String propId = (String) exchange.getProperty("ID");
String headerId = (String) exchange.getIn().getHeader("ID"); }
I leave you some examples:
<setHeader headerName="token">
<constant>someValue</constant>
</setHeader>
<setHeader headerName="userName">
<simple>${properties:userName}</simple> //from config
</setHeader>
<setProperty propertyName="bodyBkp">
<simple>${in.body}</simple>
</setProperty>
<setProperty propertyName="orderNumber">
<xpath resultType="String">//item[1]/orderNumber/text()</xpath>
</setProperty>
Getter
${exchangeProperty[orderNumber]}
${in.headers.token}
Documentation
Check the simple expression language:
http://camel.apache.org/simple.html
Sometimes looking at the test cases of Camel can be helpful as well, in particular for Spring DSL:
setProperty with Spring DSL
setHeader using XPATH with Spring DSL
simple expression language test