Get XML attribute value of property using XPath - ruby

I have a XML like the example below:
<?xml version="1.0" encoding="UTF-8" ?>
<testsuite errors="0" failures="0" name="test" tests="1" time="2.747">
<properties>
<property name="categories" value="ExampleCategory" />
<property name="timestamp" value="1519664414463" />
</properties>
<testcase classname="com.example.junit.Test" name="test" time="2.747" />
</testsuite>
Is there a way to retrieve the property tag value according to the name of the property?
Right now, I'm using something like that:
#doc.xpath('//testsuite//properties//property/#value').text
This will give me "ExampleCategory1519664414463".
I know if I use .first or [0], [1], etc, I can get the values separately, but I couldn't find a way to get the values separately according to the "name" attribute.
Anyone know how can I retrieve that?

This XPath,
//property[#name='timestamp']/#value
will select all value attributes of property elements with a name attribute value equal to 'timestamp'.

Related

how i can add values to my Adress endpoint in wso2 ESB/EI

i want to add values dynamically to adress endpoint in the proxy in wso2 ESB/EI
<address uri="mqtt:/SampleProxy?mqtt.server.host.name=thingsboard.cloud&mqtt.server.port=1883&mqtt.client.id=esb.test.sender&mqtt.topic.name=v1/devices/me/telemetry&mqtt.subscription.qos=0&mqtt.blocking.sender=true&mqtt.subscription.username=25416990;">
lets say for exemple i want to add "test" at the end of the endpoint how i can do this ?
For a similar problem, but with sending msg to rabbitmq, I created template, where i set exchangeName and routingKey dynamicaly. In the same manner, you can create your own template. You need to create Header named "To" and using XPATH concate interesting address endpoint, and for dynamic values you just use $func:{parameter name}
Something like below:
<?xml version="1.0" encoding="UTF-8"?>
<template xmlns="http://ws.apache.org/ns/synapse" name="rabbitmq.sender">
<parameter name="exchangeName"/>
<parameter name="routingKey"/>
<sequence>
<property name="OUT_ONLY" value="true" scope="default" type="STRING"/>
<header name="To"
scope="default"
expression="concat('rabbitmq:/?rabbitmq.connection.factory=CachedRabbitMQConnectionFactory&rabbitmq.exchange.name=',$func:exchangeName,'&rabbitmq.queue.routing.key=',$func:routingKey)"/>
<send/>
</sequence>
</template>
To use that, call-template mediator is needed. In brackets you can put expression, like below:
<call-template target="send.rabbitmq">
<with-param name="exchangeName" value="test"/>
<with-param name="routingKey" value="{get-property('testValue')}"/>
</call-template>

What's the difference between <filled> tag inside the <field> tag and out of it?

The <filled> tag can be written under <field> tag and also outside of the tag, under the a <form> tag.
So what's the difference between these two way of writing code?
And In which scenario this will be beneficial?
Example can be found in : http://help.voxeo.com/go/help/xml.vxml.tutorials.audio
If you write tag inside then it will be a particular handling for that tag.
If you write outside then it can be used for like multiple inputs manipulation that is caught under .
eg.
<?xml version="1.0" encoding="UTF-8"?>
<vxml version="2.1" xmlns="http://www.w3.org/2001/vxml">
<form id="get_starting_and_ending_cities">
<field name="start_city">
<grammar src="city.grxml"
type="application/srgs+xml"/>
<prompt>What is the starting city?</prompt>
</field>
<field name="end_city">
<grammar src="city.grxml"
type="application/srgs+xml"/>
<prompt>What is the ending city?</prompt>
</field>
<filled mode="all" namelist="start_city end_city">
<log><value expr="start_city"/></log>
<log><value expr="end_city"/></log>
<if cond="start_city == end_city">
<prompt>
You can't fly from and to the same city.
</prompt>
</if>
</filled>
</form>
</vxml>

Getting attribute with condition using XPath

I am using iReport 5.6.0 to generate a report with xml datasource .
I need to select the attribute date of a node that have an attribute named Type with a value of START
Since I'm new to iReport and XPath , i can't find the right XPath query .
I've tried this , but it didn't work :
<!-- language: lang-xml -->
<queryString language="xPath">
<![CDATA[/Document]]>
</queryString>
<field name="Date" class="java.lang.String">
<fieldDescription>
<![CDATA[Date/#Date[#type="START"]]]>
</fieldDescription>
</field>
Here 's my XML data file :
<!-- language: lang-xml -->
<?xml version='1.0' encoding="UTF-8"?>
<Document>
<Date Type="INV" Date="20140601" />
<Date Type="START" Date="20140201" />
</Document>
(I need the value : 20140201 to be displayed)
This is the XPath expression you're looking for:
Date[#Type="START"]/#Date
In natural language: get the Date attribute from Date elements that have a Type attribute with value "START".

XDT Config Transforms - ReplaceAll?

I've got a custom section in my web.config file similar to this structure:
<Messages>
<Message id="1'>
<Property Name="foo" value="bar" />
</Message>
<Message id="2'>
<Property Name="foo" value="bar2" />
</Message>
</Messages>
I want to apply a custom transformation on this such that I can change the value of ALL instances of the Property element with Name="foo" - but I cant seem to get it to work.
I've tried:
<Messages>
<Message>
<Property Name="foo" value="updated" xdt:Locator=Match(Name) xdt:Transform="Replace" />
</Message>
</Mesasges>
I can remove all the elements by replacing the Transform=Replace with a Transform=RemoveAll - any ideas how I can achieve something similar to replace all the values?
It seems like Transform:Replace only replaces the first matched element from the documentation on msdn: ...If more than one element is selected, only the first selected element is replaced. I solved this issue by using a combination of Match-Conditions and SetAttributes, something like:
<Messages>
<Message>
<Property value="updated" xdt:Locator=Condition(#Name='foo') xdt:Transform="SetAttributes(value)" />
</Message>
</Messages>

Working With Nested XPath Predicates ... Refined

All great answers! But the question deserves refinement ...
I've got the following sample XML ...
<objects>
<object objectId="1123" ... />
<properties refObjectId="1123" ... />
<properties refObjectId="1123" refPropertyId="2311" ... />
<properties refObjectId="1123" refPropertyId="4611" ... />
<object objectId="2123" ... />
<properties refObjectId="2123" refPropertyId="4311" ... />
<properties refObjectId="2123" refPropertyId="8611" ... />
....
</objects>
... and the following XPath query ...
//object[//properties[#refObjectId=#objectId and not(#refPropertyId)]]
I thought this query would return all object nodes where there is a properties node that has a refObjectId attribute that equals the objectId attribute of the object node and no 'refPropertyId' attribute ... namely object 1123 only, not object 2123 ... but it doesn't. It seems the #objectId in the nested predicate does not refer to the objectId attribute of the object node.
Any ideas? I know the XML structure isn't nested as you would expect, but there are reasons for this structure.
Generally you should avoid using // where you can. I'd consider rephrasing:
//object[../properties/#refObjectId=#objectId]
In the expression provided, your nested predicate is actually checking for
//properties/#refObjectId=//properties/#objectId
of which there are none.
I hope this helps!
EDIT: Since the question has been updated here is an updated response:
You added "It seems the #objectId in the nested predicate does not refer to the objectId attribute of the object node." You're absolutely right! So let's fix it!!
//object[../properties[not(#refPropertyId)]/#refObjectId=#objectId]
This should be closer to what you're after!
Try this:
//objects[object/#objectId = properties/#refObjectId]/object
This should work:
//objects/object[#objectId = ../properties/#refObjectId]
I am not sure how your xml is. However, if it is in the following format:
<objects>
<object objectId="1111" />
<properties refObjectId="1111" />
<object objectId="2111" />
<properties refObjectId="3111" />
<object objectId="4111" />
<properties refObjectId="5111" />
<object objectId="6111" />
<properties refObjectId="4111" />
<object objectId="7111" />
<properties refObjectId="7111" />
</objects>
Then you should use the following xpath to get only objects 1111 and 7111. The result should not include 4111 because the properties where refObjectId = 4111 does not immediately follow the object whose objectId=4111.
//objects/properties[#refObjectId = preceding::object[1]/#objectId]/preceding::object[1]
Assuming that all <properties> nodes that belong to a given <object> actually follow that object (your input seems to imply that), you could do:
/objects/properties[
#refObjectId = preceding-sibling::object[1]/#objectId
and
not(#refPropertyId)
]/preceding-sibling::object[1]
This should perform pretty well.
If you happen to be in XSLT, things get a lot simpler:
<xsl:key name="kPropertiesByObjectId" match="properties" use="#refObjectId" />
and
<xsl:template match="object">
<!-- This tests for an empty node-set. Non-empty node sets can only happen
for objects with at least one <properties> node without #refPropertyId -->
<xsl:if test="key('kPropertiesByObjectId', #objectId)[not(#refPropertyId)]">
<xsl:copy-of select="." />
</xsl:if>
</xsl:template>
In the XSLT case, the order of object and proerties nodes becomes irrelevant.

Resources