<Item>
<ASIN>0545010225</ASIN>
<DetailPageURL>http://www.amazon.com/Harry-Potter-Deathly-Hallows-Book/dp/0545010225%3FSubscriptionId%3DAKIAJ5YASVREOJN4AKXQ%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0545010225</DetailPageURL>
<ItemAttributes>
<Author>J.K. Rowling</Author>
<Creator Role="Illustrator">Mary GrandPré</Creator>
<Manufacturer>Arthur A. Levine Books</Manufacturer>
<ProductGroup>Book</ProductGroup>
<Title>Harry Potter and the Deathly Hallows (Book 7)</Title>
</ItemAttributes>
</Item>
I need to show the ASIN of all items authored by J.K. Rowling. This is an example of one of the books that would fall into this category. What would be the Xpath that would accomplish this?
Here is an XPath expression for the ASIN numbers of all Items authored by J.K. Rowling:
/Item[ItemAttributes/Author = 'J.K. Rowling']/ASIN
Related
Write an expression that selects all the items ISBN and TITLE that their return
is “3/12/2017”
Code -
<itemlist>
<item>
<title>
The Bonfire of the Vanities
</title>
<type>Book</type>
<authors>
<author>Wolfe, Tom</author>
</authors>
<subjects>
<subject>New York</subject>
<subject>Race Relations</subject>
</subjects>
<isbn>0374115370</isbn>
<location>Adult</location>
<collection>Fiction</collection>
<status return="3/12/2017">Checked Out</status>
</item>
</itemlist>
//itemlist/item[status/#return='3/12/2017']/(isbn|title)
Find item elements whose status element child has return attribute that is "3/12/2017", then take those items' children that are isbn or title elements.
Problem : select data based on node which is in another part of the tree
How to select data in rows of column with label = "status"?
Data should be "data2" from /result/rows/items/item/c/items/item/v
and selection should be based on label='status' i.e. /result/cols/items/item/label=status
In the XML below "status" is column number 2, but it may change to column number 1, so the according XPath should return data of column no.1
<result>
<cols>
<items>
<item>
<id>c1</id>
<label>result</label>
<type>string</type>
</item>
<item>
<id>c2</id>
<label>status</label>
<type>string</type>
</item>
<item>
<id>c3</id>
<label>message</label>
<type>string</type>
</item>
</items>
</cols>
<rows>
<items>
<item>
<c>
<items>
<item>
<v>data1</v>
</item>
<item>
<v>data2</v>
</item>
<item>
<v />
</item>
</items>
</c>
</item>
</items>
</rows>
</result>
Your description is not very clear to understand.
I got it like this:
There is a node which indicates the column. The label of the column is "status". You get this label with
/result/cols/items/item/label[text()='status']
But that's not what you want. First, you want to find out at which position that column is. You get that position with
count(/result/cols/items/item[label/text()='status']/preceding-sibling::*)+1
But that's still not what you want. Based on that information, you want to select the actual data within rows. You get a row with
/result/rows/items/item/c/items/item[2]/v/text()
But you don't always want the second column of the row, you want the row based on the column index determined earlier. So you need to combine both:
/result/rows/items/item/c/items/item[count(/result/cols/items/item[label/text()='status']/preceding-sibling::*)+1]/v/text()
The last expression does not contain any hard coded indexes and uses only the column header text "status" to determine where the data is. In your example, it returns data2. If you change the column header text to "result", it gives you data1.
I'm not sure what you are asking for. But if you are looking for an Expression, which will get the "type" text for all labels with the text "status"
//label[text()='status']/following-sibling::type
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).
I have the decision tree structure as such like the below ,
<?xml version="1.0" encoding="utf-8" ?>
<root>
outlook
<item>
sunny
<root>
humidity
<item>
high
<leaf>no</leaf>
</item>
<item>
normal
<leaf>yes</leaf>
</item>
</root>
</item>
<item>
overcast
<leaf>yes</leaf>
</item>
<item>
rain
<root>
wind
<item>
weak
<leaf>yes</leaf>
</item>
<item>
strong
<leaf>no</leaf>
</item>
</root>
</item>
</root>
I wanted a LINQ query which will display ,
Outlook : Sunny , Overcast , Rain
That is , root value plus the tree's first level of children's value. Again selecting a particular item like ,
Sunny
It must iteratively give its successive root value and root's first level of children. That is ,
Humidity : High , Normal
And finally arrive at the decision , YES or NO.
Am working on the same but some inputs would help me further.
Could you try the following:
var doc = XDocument.Parse(xml);
foreach (var r in doc.Descendants("root"))
{
var values = r.Elements("item").Select(s => (s.FirstNode as XText).Value.Trim()).ToList();
string.Concat((r.FirstNode as XText).Value.Trim(), ": ", string.Join(",", values)).Dump("decision");
}
This is output I get:
decision
outlook: sunny,overcast,rain
decision
humidity: high,normal
decision
wind: weak,strong
I used LinqPad, hence the Dump method call which spits the output to the LinqPad console. Hope this helps.
The XPath bookstore/book[1] selects the first book node under bookstore.
How can I select the first node that matches a more complicated condition, e.g. the first node that matches /bookstore/book[#location='US']
Use:
(/bookstore/book[#location='US'])[1]
This will first get the book elements with the location attribute equal to 'US'. Then it will select the first node from that set. Note the use of parentheses, which are required by some implementations.
Note, this is not the same as /bookstore/book[1][#location='US'] unless the first element also happens to have that location attribute.
/bookstore/book[#location='US'][1] works only with simple structure.
Add a bit more structure and things break.
With-
<bookstore>
<category>
<book location="US">A1</book>
<book location="FIN">A2</book>
</category>
<category>
<book location="FIN">B1</book>
<book location="US">B2</book>
</category>
</bookstore>
/bookstore/category/book[#location='US'][1] yields
<book location="US">A1</book>
<book location="US">B2</book>
not "the first node that matches a more complicated condition". /bookstore/category/book[#location='US'][2] returns nothing.
With parentheses you can get the result the original question was for:
(/bookstore/category/book[#location='US'])[1] gives
<book location="US">A1</book>
and (/bookstore/category/book[#location='US'])[2] works as expected.
As an explanation to Jonathan Fingland's answer:
multiple conditions in the same predicate ([position()=1 and #location='US']) must be true as a whole
multiple conditions in consecutive predicates ([position()=1][#location='US']) must be true one after another
this implies that [position()=1][#location='US'] != [#location='US'][position()=1]
while [position()=1 and #location='US'] == [#location='US' and position()=1]
hint: a lone [position()=1] can be abbreviated to [1]
You can build complex expressions in predicates with the Boolean operators "and" and "or", and with the Boolean XPath functions not(), true() and false(). Plus you can wrap sub-expressions in parentheses.
The easiest way to find first english book node (in the whole document), taking under consideration more complicated structered xml file, like:
<bookstore>
<category>
<book location="US">A1</book>
<book location="FIN">A2</book>
</category>
<category>
<book location="FIN">B1</book>
<book location="US">B2</book>
</category>
</bookstore>
is xpath expression:
/descendant::book[#location='US'][1]
<bookstore>
<book location="US">A1</book>
<category>
<book location="US">B1</book>
<book location="FIN">B2</book>
</category>
<section>
<book location="FIN">C1</book>
<book location="US">C2</book>
</section>
</bookstore>
So Given the above; you can select the first book with
(//book[#location='US'])[1]
And this will find the first one anywhere that has a location US. [A1]
//book[#location='US']
Would return the node set with all books with location US. [A1,B1,C2]
(//category/book[#location='US'])[1]
Would return the first book location US that exists in a category anywhere in the document. [B1]
(/bookstore//book[#location='US'])[1]
will return the first book with location US that exists anywhere under the root element bookstore; making the /bookstore part redundant really. [A1]
In direct answer:
/bookstore/book[#location='US'][1]
Will return you the first node for book element with location US that is under bookstore [A1]
Incidentally if you wanted, in this example to find the first US book that was not a direct child of bookstore:
(/bookstore/*//book[#location='US'])[1]
Use the index to get desired node if xpath is complicated or more than one node present with same xpath.
Ex :
(//bookstore[#location = 'US'])[index]
You can give the number which node you want.
if namespace is provided on the given xml, its better to use this.
(/*[local-name() ='bookstore']/*[local-name()='book'][#location='US'])[1]
for ex.
<input b="demo">
And
(input[#b='demo'])[1]
With help of an online xpath tester I'm writing this answer...
For this:
<table id="t2"><tbody>
<tr><td>123</td><td>other</td></tr>
<tr><td>foo</td><td>columns</td></tr>
<tr><td>bar</td><td>are</td></tr>
<tr><td>xyz</td><td>ignored</td></tr>
</tbody></table>
the following xpath:
id("t2") / tbody / tr / td[1]
outputs:
123
foo
bar
xyz
Since 1 means select all td elements which are the first child of their own direct parent.
But the following xpath:
(id("t2") / tbody / tr / td)[1]
outputs:
123