How to find same elements with xpath - xpath

With the next xml, how coud i get the list of directors where two directors has the same LastName in one movie?
<MoviesLib>
<Movie Title="Batman" Year="2013">
<Directors>
<Director>
<Name>Robert</Name>
<LastName>Zemeckis</LastName>
</Director>
</Directors>
</Movie>
<Movie Title="Gru" Year="2012">
<Directors>
<Director>
<Name>john</Name>
<LastName>tailer</LastName>
</Director>
<Director>
<Name>Emma</Name>
<LastName>Smith</LastName>
</Director>
<Director>
<Name>Lana</Name>
<LastName>Smith</LastName>
</Director>
</Directors>
</Movie>
</MoviesLib>
for example in this case would be: Emma Smith, Lana Smith
thanks

The following XPath 2.0 expression should work:
for $d in //Director
return $d[../Director[not(. is $d) and LastName = $d/LastName]]
I can't come up with a single XPath 1.0 expression since it doesn't support for expressions (see the question How to get the context of outer predicate? for some background).

Related

JMeter Xpath2 extractor id's matching multiple conditions

Below is the sample XML fragment, from it i'm trying to filter out id's of articles matching both conditions as below. Currently i could extract id's for individual condition with help of expression below
get Avaialable articles, Xpath2 expression = (//*//*//*//*[starts-with(state,'Avaialable')])/id
get articles name starting with 'A' () , Xpath2 expression = (//*//*//*//*[starts-with(name,'A')])/id
I want to merge these conditions in a single expression and would like to
fetch id's of Articles where Name starts with 'A' AND articles which
are Available
. Tried multiple ways but not working as expected.
Dummy XML fragment:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:GetArtclesResponse
xmlns:ns2="XXX"
xmlns:ns4="XXX"
xmlns:ns3="XXX"
xmlns:ns6="XXX"
xmlns:ns5="XXX"
xmlns:ns8="XXX"
xmlns:ns7="XXX"
xmlns:ns13="XXX"
xmlns:ns9="XXX"
xmlns:ns12="XXX"
xmlns:ns11="XXX">
<serverTimeInfo timezone="+00:00" timestamp="1606409365419"/>
<items>
<count>2</count>
<articles>
<article>
<name>ABC</name>
<id>1234</id>
<state>Avaialable</state>
</article>
<article>
<name>XYZ</name>
<id>3456</id>
<state>Avaialable_Conditional</state>
</article>
</articles>
</items>
</ns3:GetArtclesResponse>
You can use and to check both:
(//*//*//*//*[starts-with(state,'Avaialable') and starts-with(name,'A')])/id
If you want to combine 2 different XPath expressions you can use | (union) operator like:
//article[state = 'Avaialable'] | //article[starts-with(name,'A')]
it will return you both:
nodes which have state=Available
and nodes which name starts with A
If you want to combine 2 conditions in a single XPath expression - go for and operator like:
//article[state = 'Avaialable' and starts-with(name,'A')]
it will return
nodes which nave state=available and whose name attribute starts with a
More information:
XPath Operators
The JMeter XPath2 Extractor: How to Achieve Better Correlations

How to XPATH select a list of Uncles

Im kind of new to xpath, so... sorry in advance if something is not referred to accurately...
I would like to formulate an xpath query which will select the 'uncle' of each element of a specific name:
Say I have the following XML:
<aaa>
<bbb>
<first_uncle>
uncle_bob
</first_uncle>
<ccc>
<ddd>d_val_1</ddd>
</ccc>
<ccc>
<ddd>d_val_2</ddd>
</ccc>
<ccc>
<ddd>d_val_3</ddd>
</ccc>
</bbb>
<bbb>
<first_uncle>
uncle_jack
</first_uncle>
<ccc>
<ddd>d_val_4</ddd>
</ccc>
<ccc>
<ddd>d_val_5</ddd>
</ccc>
</bbb>
</aaa>
I would like to have an output which lists the 'first_uncle' of each ddd.
Something like this:
uncle_bob
uncle_bob
uncle_bob
uncle_jack
uncle_jack
My trials (//ccc/ddd/../../*[1]) gave me a list of 'unique uncles':
uncle_bob
uncle_jack
Thanks!
In XPath 1.0, a single XPath expression can only select a set of actual nodes. It can't select the same nodes multiple times, and there are only two first_uncles in your XML.
So you would need to do this in two steps (pseudocode, since you haven't told us what language or XML library you're using):
var people = doc.select('/aaa/bbb/ccc/ddd');
foreach (var person in people) {
var uncle = person.selectSingle('../../first_uncle');
// use uncle
}

Xpath: return all nodes that match any one of the conditions

I am trying to fetch two nodes from XML as combined result using OR condition.
Nodes in XML where name = John or name="jim",both should be returned . So basically I expect following result:
<person name="John"></person>
<person name="Jim"></person>
I have tried XPath function * ///person[#name="John"] or ///person[#name="Jim"]*
but it gives me only one node.
How to construct Xpath function in this case ?
regards,
Venky
I would use a predicate person[#name = ('John', 'Jim')] if we assume Saxon means a Saxon 9 version where XPath 2 or 3 is supported. Of course the right place for your or expression would be inside the square brackets person[#name = 'Jim' or #name = 'John'].

Select distinct values with Xpath

Im using this Xpath query
//li[contains(#class, 'cmil_header')]/span[contains(#class, 'cmil_theatre')] and the result of this query is:
Park
Saga Tokey
Latvia
Latvia
Skande
Paramount
Paramount
Paramount
Oslo
Oslo
...
I have been searching and i have come to conclusion that there is a option to select unique or distinct nodevalues/items with Xpath. But i can't get it to work.
I have managede to be able to select specific item with //li[contains(#class, 'cmil_header')][1]/span[contains(#class, 'cmil_theatre')] (Park in this case), and i thought //li[contains(#class, 'cmil_header')][distinct-values()]/span[contains(#class, 'cmil_theatre')] would work, but not.
My question:
How would my query be to reproduce:
Park
Saga Tokey
Latvia
Skande
Paramount
Oslo
...
Edit: pastabin with sample
http://pastebin.com/a3x7hRFu
XPath 1.0 solution (where there is no distinct-values function) that relies on the duplicates being sequential:
//li[contains(#class, 'cmil_header')]/span[contains(#class, 'cmil_theatre') and (not(../preceding-sibling::li[contains(#class, 'cmil_header')]) or ../preceding-sibling::li[contains(#class, 'cmil_header')][1]/span[contains(#class, 'cmil_theatre')]/text() != ./text())]
find all li nodes that contain the cmil_header class: //li[contains(#class, 'cmil_header')]
find the child span nodes that contain the cmil_theatre class: /span[contains(#class, 'cmil_theatre') and
where there is no previous li node containing the cmil_header class: (not(../preceding-sibling::li[contains(#class, 'cmil_header')])
or the previous li node containing the cmil_header class has a span node child that contains the cmil_theatre class: or ../preceding-sibling::li[contains(#class, 'cmil_header')][1]/span[contains(#class, 'cmil_theatre')]
and the text content of that span is not the same as the text content of... : /text() !=
...this span: ./text())]
i thought //li[contains(#class, 'cmil_header')][distinct-values()]/span[contains(#class, 'cmil_theatre')] would work, but not.
No, there is no way this could work. I find it hard to know what you were imagining. The most basic error is that distinct-values() expects an argument. More subtly, you really don't seem to have understood how predicates (expressions in square brackets) work.
What would work -- assuming your XPath processor supports XPath 2.0 -- is
distinct-values(//li[contains(#class, 'cmil_header')]/
span[contains(#class, 'cmil_theatre')])

Get nodes from xml string using regex

I have string xml like below:
<Query>
<Code>USD</Code>
<Description>United States Dollars</Description>
<UpdateTime>2013-03-04 02:27:33</UpdateTime>
<toUSD>1</toUSD>
<USDto>1</USDto>
<toEUR>2</toEUR>
<EURto>3</EURto>
</Query>
All text is in one line without white spaces. I can't write right regex pattern. I want get nodes which begin like <to. For example <toEUR>, <toUSD>.
How should I write this pattern?
With nokogiri and the xpath function starts-with:
require 'nokogiri'
doc = Nokogiri::XML <<EOF
<Query>
<Code>USD</Code>
<Description>United States Dollars</Description>
<UpdateTime>2013-03-04 02:27:33</UpdateTime>
<toUSD>1</toUSD>
<USDto>1</USDto>
<toEUR>2</toEUR>
<EURto>3</EURto>
</Query>
EOF
doc.search('//*[starts-with(name(),"to")]').map &:to_s
#=> ["<toUSD>1</toUSD>", "<toEUR>2</toEUR>"]
Although the general consensus is that parsing xml etc with regex is not the way to go, something like this should do the trick:
<\s*(to[^>\s]+)[^>]*>([^<]+)<\s*/\s*\1\s*>
In ruby format:
/<\s*(to[^>\s]+)[^>]*>([^<]+)<\s*\/\s*\1\s*>/
Matches <toWatever>value</toWhatever> back-reference group 1 returns the name (toWhatever) and back-reference group 2 returns the value.

Resources