Get all preceding and following siblings for a given node - xpath

I have the following XML snippet:
<root>
<CharacteristicUse>
<UseArea>Specification_Characteristics</UseArea>
<Value>
<ValueID>123</ValueID>
</Value>
<Value>
<ValueID>444</ValueID>
</Value>
<Value>
<ValueID>555</ValueID>
</Value>
<Value>
<ValueID>777</ValueID>
</Value>
<Value>
<ValueID>888</ValueID>
</Value>
</CharacteristicUse>
</root>
I want to be able to get all preceding and following siblings of the Value node which has its child node ValueID with text = 555
I have been trying to combine the following way:
/root/CharacteristicUse/Value[ValueID='555']/following-sibling::* | preceding-sibling::*
But, it only returns to me the following siblings.
Is it possible to have one single query to get the output as:
<Value>
<ValueID>123</ValueID>
</Value>
<Value>
<ValueID>444</ValueID>
</Value>
<Value>
<ValueID>777</ValueID>
</Value>
<Value>
<ValueID>888</ValueID>
</Value>

One way is brute-force:
/root/CharacteristicUse/Value[ValueID='555']/preceding-sibling::* | /root/CharacteristicUse/Value[ValueID='555']/following-sibling::*
This includes the "UseArea" node also, not sure if you want that.
Or if what you want is just all the values that are NOT a particular value, then
/root/CharacteristicUse/Value[not(ValueID='555')]
is more direct.

I found the answer.
The xpath looks like:
/root/CharacteristicUse/Value[ValueID='555']/following-sibling::Value | /root/CharacteristicUse/Value[ValueID='555']/preceding-sibling::Value

Related

how i can put two filter conditions where name='SHIPMENT.ORDERS.ORREFNUMS.REFNUM_VALUE' and value node contains ":" in the value

i want to filter where name=SHIPMENT.ORDERS.ORREFNUMS.REFNUM_VALUE and contains ":" in the value.
<inputData name="SHIPMENT.ORDERS.ORREFNUMS.REFNUM_VALUE" xmlns="http://xmlns.oracle.com/apps/otm/ExternalRating">
<values xmlns="http://xmlns.oracle.com/apps/otm/ExternalRating">
<value xmlns="http://xmlns.oracle.com/apps/otm/ExternalRating">24-100</value>
<value xmlns="http://xmlns.oracle.com/apps/otm/ExternalRating">RC3.B726030-001-CO8MODF183896704</value>
<value xmlns="http://xmlns.oracle.com/apps/otm/ExternalRating">Y</value>
<value xmlns="http://xmlns.oracle.com/apps/otm/ExternalRating">2022-06-23 23:59:59</value>
</values>
</inputData>
Depending on the actual structure of <values> you could, as specified in your question, use:
//inputData[#name="SHIPMENT.ORDERS.ORREFNUMS.REFNUM_VALUE"]//value[contains(.,":")]/text()
If the datetime element is always the 4th <value> you can try:
//inputData[#name="SHIPMENT.ORDERS.ORREFNUMS.REFNUM_VALUE"]//value[4]/text()
or, if it's always the last <value>:
//inputData[#name="SHIPMENT.ORDERS.ORREFNUMS.REFNUM_VALUE"]//value[last()]/text()

How can I compare map-like elements with XMLUnit

I have below xml data:
Control:
<Data>
<propertyValues>
<propertyName>Name1</propertyName>
<value>
<text>
<value>Value1</value>
</text>
</value>
</propertyValues>
<propertyValues>
<propertyName>Name2</propertyName>
<value>
<text>
<value>Value2</value>
</text>
</value>
</propertyValues>
</Data>
Test:
<Data>
<propertyValues>
<propertyName>Name2</propertyName>
<value>
<text>
<value>Value2</value>
</text>
</value>
</propertyValues>
<propertyValues>
<propertyName>Name1</propertyName>
<value>
<text>
<value>Value1</value>
</text>
</value>
</propertyValues>
</Data>
And I would expect these 2 documents are "same".
How can I config xmlUnit to make it work? (I'm using xmlunit 2.6.3)
Thanks
Leon
This is pretty similar to the running example of the "Selecting Nodes" part of XMLUnit's User Guide.
You need to use an ElementSelector that picks the correct propertyValues element when looking at the list of elements and then decides to compare the elements that contain the same nested text inside the only child element named propertyName. This directly translates into
ElementSelectors.conditionalBuilder()
.whenElementIsNamed("propertyValues")
.thenUse(ElementSelectors.byXPath("./propertyName", ElementSelectors.byNameAndText))
...
and then you need to add whatever other rules are required to make the rest work. Looking at the visible rest of your example there are no ambiguous children and a simple
...
.elseUse(ElementSelectors.byName)
.build();
will do.

Arithmetic operation in xpath on array of elements

I have a requirement to sum amount from every element i have in my response using xpath
,however condition is i am not sure about how many tags I am going to get in my response.
Sum= amount1*value1+ amount2*value2+amount3*value3+....
<root>
<element>
<amount>10</amount>
<value>2</value>
</element>
<element>
<amount>20</amount>
<value>2</value>
</element>
<element>
<amount>30</amount>
<value>2</value>
</element>
</root>
can some one please help?
You can try below XPath to get summ of all amount nodes:
sum(//element/amount)
Considering updated question:
sum(//element/sum(./amount * ./value))

Xpath 1.0: Cannot get the value of a specific element. Duplicate values returned

I have the following piece of XML:
<Resource>
<ResourceSummaryBag>
<Entry>
<ObjectName>NR_LDI</ObjectName>
<usage_prm>
<Entry>
<UsedEntries>98416</UsedEntries>
</Entry>
</usage_prm>
</Entry>
<Entry>
<ObjectName>R_LDI</ObjectName>
<usage_prm>
<Entry>
<UsedEntries>13265</UsedEntries>
</Entry>
</usage_prm>
</Entry>
</ResourceSummaryBag>
</Resource>
I want to extract usage_prm/UsedEntries values by ObjectName element.
If I use contains, I get duplicate values for 'R_LDI' object but I want the values for the specific R_LDI and NR_LDI objects.
Resource/ResourceSummaryBag/Entry[./ObjectName[contains(.,'R_LDI')]]/usage_prm/Entry/UsedEntries
Result: 98416 13265
Any solution?
Thanks in advance for any help.
Use = + normalize-space() instead of contains():
./ObjectName[normalize-space()='R_LDI']
normalize-space() strips leading and trailing white-space from a string, replaces sequences of whitespace characters by a single space, and returns the resulting string [MDN]

XPATH expression that Matches on the attribute value "true"

I have some XML like this:
<engine-set>
<engine host-ref="blah1.com">
<property name="foo" value="true"/>
<property name="bar" value="true"/>
</engine>
<engine host-ref="blah2.com">
<property name="foo" value="true"/>
<property name="bar" value="false"/>
</engine>
</engine-set>
I want to match on all engine elements that have a child node property with a name equal to "bar" and and value equal to "true". I'm finding the fact that "true" appears in my XML is causing my condition to always evaluate to true in an XPath expression. Is there a way around? I'm using Python and lxml.
EDIT:
My xpath expression is (that isn't working) is:
//engine[(property/#name='bar' and property/#value="true")]
Thanks,
I want to match on all engine elements
This is:
//engine
that have a child node property
Now this becomes:
//engine[property]
with a name equal to "bar"
Still more specific:
//engine[property[#name = 'bar']]
and and value equal to "true".
Finally:
//engine[property[#name = 'bar' and #value = 'true']]
So you're saying
//engine[property[#name='bar' and #value='true']]
gives you too many results? Because for me it gives just one.
What XPath expression did you try?
The following seems to work well in getting "blah1.com" but not "blah2.com":
//engine[property[#value="true"][#name="bar"]]
Remember that you need to encase your parameter test values in quotes.

Resources