The input looks like below,
<book author="ABC" type="Children">
<id>123</id>
<name>XYZ</name>
</book>
I have set the above in property in an xml route as:
<camel:setProperty propertyName="REQUEST">
<camel:xpath>/node()</camel:xpath>
</camel:setProperty>
Then I do some other processing and based on the new response I want to extract the value of an author(i.e. ABC) from this Property and compare it with a element's text string from the response.
I tried a few ways using camel:xpath and camel:simple but am not able to extract the value from property.
What is the correct way to extract this property?
To access the REQUEST property using simple you can do this:
${property.REQUEST}
To access properties using xpath:
<camel:xpath>
function:properties("REQUEST")/[add your xpath expression here]
</camel:xpath>
More info on the properties function can be found here - https://camel.apache.org/xpath.html
I don't know if it's possible using properties, but you should be able to do it with headers.
Firstly:
<setHeader headerName="REQUEST">
<xpath>/node()</xpath>
</setHeader>
Then if you wanted to set another header with just the author value:
<setHeader headerName="REQUEST2">
<xpath headerName="REQUEST" resultType="java.lang.String">/book/#author</xpath>
</setHeader>
Or if you wanted to evaluate the value as a <choice> condition:
<when>
<xpath headerName="REQUEST">/book/#author = 'ABC'</xpath>
Related
I retrieve XPath from a database (via DSS) and I need to apply it to the body. Is this somehow possible?
To give an example, let's say I have this xml request
<custom>
<id>24</id>
<text>Some Text</text>
<firstOccurId>123456</firstOccurId>
<secondOccurId>654321</secondOccurId>
</custom>
I take ID (24) and call template, which will return
<replacements>
<row>
<value>ABCDEFG</value>
<xpath>/*/custom/firstOccurId</xpath>
</row>
<row>
<value>GFEDCDBA</value>
<xpath>/*/custom/secondOccurId</xpath>
</row>
</replacements>
now I need to apply xpath to request and change it's value, so the transformed request body looks like this
<custom>
<id>24</id>
<text>Some Text</text>
<firstOccurId>ABCDEFG</firstOccurId>
<secondOccurId>GFEDCDBA</secondOccurId>
</custom>
I tried both evaluate() and put XPath string inside {{}} in Call Template mediator, but both without success.
evaluate() is the correct answer. To be more specific, for this example I need to store custom request in property, get replacements, loop through them and inside this loop I need to store full xpath in property as fn:concat('$body', //el:row/el:xpath, '/text()'), enrich body with original payload and apply stored xpath as evaluate()
I have nifi processor EvaluateXpath and i want to get tags value from xml response , for it i use expression like this //count/text() but my count attribute is still empty , what should i change?
my xml reponse is something like this, AND I WANT TO GET THIS 72 AND WRITE IT IN MY COUNT ATTRIBUTE .
<SendMessage xmlns="http://www.talk.gov.uk/CM/envelope">
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
<Class></Class>
<Qualifier>response</Qualifier>
<Function>submit</Function>
<CorrelationID></CorrelationID>
<ResponseEndPoint/>
</MessageDetails>
<SenderDetails>
<IDAuthentication/>
<EmailAddress/>
</SenderDetails>
</Header>
<MessageDetails/>
<Body>
<Message xmlns="http://www.govtalk.gov.uk/CM/envelope">
<getEventDataResponse xmlns="http://www.talk.gov.uk/CM/envelope" xmlns:ns2="" xmlns:ns3="http://www.talk.gov.uk/CM/envelope" xmlns:ns4="http://www.talk.gov.uk/CM/envelope">
<count>72</count>
</Message>
you have namespace in your message xmlns="http://www.talk.gov.uk/CM/envelope"
it means that the name of count node is {http://www.talk.gov.uk/CM/envelope} count
the nifi processor EvaluateXPath 1.3.0 does not support namespaces however you can write your xpath like this to search for the element by local name:
//*[local-name()='count']/text()
I want remove an xml attribute via xpath, but
the xml element could have more atrributes in the future.
html code:
<p class="red, blue, green">test/<p>
xpath:
<xpath expr="//p[contains(#class, 'green')]" position="attributes">
<attribute name="class">red, blue</attribute>
</xpath>
Is where a better way for fixtext "red, blue"?
In order to suppport possible new version of the html file like
"<p class="red, blue, green, brown">test</p>" in the future without need to change the xpath code again.
for instance actual attribute list as var + an xpath function
What about setting the #class to
concat(substring-before(#class, "green"), substring-after(#class, "green"))
You'll need to solve the abandoned commas, too, but as Björn Tantau commented, in real HTML the classes would be separated by spaces, so you can just wrap the result into normalize-space.
I am having the following XML structure:
<xml>
<value>b</value>
<objects>
<object>
<value>a</value>
</object>
<object>
<value>b</value>
</object>
</objects>
</xml>
What I want is to select the second object, based on the value in the xml.
This XPath works:
//xml/objects/object[value = 'b']
This XPath does not return results:
//xml/objects/object[value = //xml/value/text()]
Are nested XPath expressions not supported?
They are, but the search within a predicate is always relative to the context you currently in.
Currently you start looking for an <xml/> element which is a child of <object/> and as there is none it will yield an empty result set.
Using ../ or parent::* you can go an axis step up to the parent and can select the required value:
//xml/objects/object[value = ../../value]
Given this XML fragment (I've removed superfluous fluff):
<Event name="DataComplete">
<Task id="d20a0053-7678-43ba-bc8a-ece24dcff15b"/>
<DataItems>
<DataItem name="Survey" type="task">
<Value status="NotStarted" taskId="00000000-0000-0000-0000-000000000000" />
</DataItem>
<GroupDataItem name="CT_Visit"> --- this may repeat
<ItemGroup id="1" >
<DataItem name="Special Contractor" type="string">Yes</DataItem>
What xPath expression will determine if any DataItem with name="Special Contractor" has the value "Yes".
I'm trying something like this:
Yes = /Event/Task/DataItems/GroupDataItem/ItemGroup/DataItem/#[normalize-space() = 'Special Contractor']
and many variations usually resulting in "invalid xPath expression".
Any clues most welcome. Thanks!
[EDIT]
Thanks for the answers Jiri and Will. Will was close, but as my question states, I'm trying to determine if any* element has the value Yes. I should have been more explicit in saying that I need a boolean, true or false. Adapting Will's answer led me to this:
"Yes" = //Event/Task/DataItems/GroupDataItem/ItemGroup/DataItem[#name='Special Contractor']
This returns a simple Boolean='true' or Boolean='false'.
Thanks guys!
/Event/DataItems/GroupDataItem/ItemGroup/DataItem[#name = "Special Contractor"][. = "Yes"]
Returns the DataItem in question. Note that this will be a sequence of matching DataItem elements if there are more than one. If you just want a boolean:
exists(/Event/DataItems/GroupDataItem/ItemGroup/DataItem[#name = "Special Contractor"][. = "Yes"])
(as an aside; I removed Task from the xpath, since it's not actually an ancestor of the DataItem in the XML fragment you posted, even though the indentation makes it look like it is.)
Use this xpath
/Event/Task/DataItems/GroupDataItem/ItemGroup/DataItem[#name='Special Contractor']
for following xml:
<Event name="DataComplete">
<Task id="d20a0053-7678-43ba-bc8a-ece24dcff15b">
<DataItems>
<DataItem name="Survey" type="task">
<Value status="NotStarted" taskId="00000000-0000-0000-0000-000000000000" />
</DataItem>
<GroupDataItem name="CT_Visit"> --- this may repeat
<ItemGroup id="1" >
<DataItem name="Special Contractor" type="string">Yes</DataItem>
</ItemGroup>
</GroupDataItem>
</DataItems>
</Task>
...
</Event>
If the task is really non-pair element, then omit it from the xpath expression.