XPath Search relating to Attributes - xpath

I want to create an XPath query that returns cast members whose "job" is "Actor" and whose "order" is between "0" and "4" from the following XML. I'm finding it hard to create a query that does both.
<cast>
<person name="David Silverman" character="" job="Director" order="0"/>
<person name="James L. Brooks" character="" job="Author" order="0"/>
<person name="Dan Castellaneta" character="Homer J. Simpson" job="Actor" order="0"/>
<person name="Julie Kavner" character="Marge Simpson" job="Actor" order="1"/>
<person name="Nancy Cartwright" character="Bart Simpson" job="Actor" order="2"/>
<person name="Yeardley Smith" character="Lisa Simpson" job="Actor" order="3"/>
<person name="Dan Castellaneta" character="Krusty the Clown" job="Actor" order="4"/>
<person name="Hank Azaria" character="Moe Szyslak" job="Actor" order="5"/>
<person name="Dan Castellaneta" character="Apu Nahasapeemapetilon" job="Actor" order="6"/>
</cast>

cast/person[#job="Actor" and #order >= 0 and #order <= 3]
returns the four Simpsons you want.

You could use //cast/person[#job='Actor' and position()<3].

You should be able to combine your predicates //cast/person[#job='Actor' and #order>=0 and #order<=3]

Related

How to compare element position in xpath

I am trying to compare customer account values to display only different values and ignore duplicate in XPath:
XML code:
<info>
<Customer CustAccount="1"/>
<Customer CustAccount="2"/>
<Customer CustAccount="2"/>
<Customer CustAccount="3"/>
</info>
The result should compare customer 1/2/3 and display:
customer 1
customer 2
customer 3
You can achieve this with the XPath-2.0 expression
for $c in distinct-values(/info/Customer/#CustAccount) return concat('customer ',$c,'
')
Output is:
customer 1
customer 2
customer 3
If you do not like the newlines, remove the
from the expression.
There is no pure XPath-1.0 expression achieving this; you could only do this with XSLT-1.0 if XPath-2.0 is unavailable.
Here is the pure xpath 1.0 solution.
Sample xml:
<root >
<info>
<Customer CustAccount="1"/>
<Customer CustAccount="2"/>
<Customer CustAccount="2"/>
<Customer CustAccount="3"/>
</info>
</root>
xpath 1.0:
/root/info/Customer[not(./#CustAccount=preceding::Customer/#CustAccount)]
Evidence:

Xquery 1.0 - query to get the average of some elements, and put that average back in the same place

So I have an XML file like this:
<data>
<person name="john" lastname="doe" >
<grades>
<math>90</math>
<biology>23</biology>
</grades>
</person>
.
.
I know how to query this to get the average of all the grades, but I want to take that average and put it in the exact same place that grades are in for the original xml file, replacing grades. So I would have something like:
<data>
<person name="john" lastname="doe" >
<average>56.5</average>
</person>
.
.
edit: I actually figured out a way to get the needed results internally, thanks for the suggestion to this problem though, it may help me in the future.
As mentioned in the comment, XQuery can't literally returns modified XML. You will have to recreate the XML, and this get overly complicated given a complex XML document to start.
For this fairly simple XML structure though, you can use the following XQuery to return the expected XML :
<data>
{
for $p in /data/person
let $g := $p/grades/*
return
<person>
{
$p/#*,
<average>{sum($g) div count($g)}</average>
}
</person>
}
</data>
xpathtester demo

Linq to XML - get elements that have certain child element

Using LINQ to XML, how do I get a collection of all elements that have a named child element.
for example;
<root>
<Garage>
<Car id="001">
<Price PaymentType="Cash">$100</Price>
</Car>
<Car id="002">
<Price PaymentType="Cash">$200</Price>
</Car>
<Car id="003">
</Car>
</Garage>
</root>
this will return 2 Car elements (#1 and #2) as they have the Price element. It won't return Car #3, as it doesn't have a price element.
thanks as always
Assuming you have an XDocument object named doc with your example xml loaded into it. You could try something like this.
IEnumerable<XElement> elements = doc.Descendants("Garage").Elements().Where(e => e.Elements().Any());

How to loop in a xml structure with xquery?

the xml is like this:
<persons>
<person>
<name/>
<surname/>
</person>
<person index=1>
<name/>
<surname/>
</person>
<person index=2>
<name/>
<surname/>
</person>
...
</persons>
I need to build a view that shows all data of all persons.
name surname
name1 surname1
How can i do this loop in a select statement? It needs to be a view.
Use:
string-join(/*/person/concat(name, ' ', surname), '
')
when this XPath expression is evaluated, against the following XML document:
<persons>
<person index="1">
<name>Alex</name>
<surname>Brown</surname>
</person>
<person index="2">
<name>Katie</name>
<surname>Smith</surname>
</person>
<person index="3">
<name>Julius</name>
<surname>Caesar</surname>
</person>
</persons>
the result is:
Alex Brown
Katie Smith
Julius Caesar
Have you considered using xslt if you need a transformation?
If you need to xquery, to select these nodes then,
doc("file.xml")/persons/person/name | /persons/person/name
OR
doc("file.xml")//name |// surname
i.e. Name, Surname occuring anywhere

XPath: How to check multiple attributes across similar nodes

If I have some xml like:
<root>
<customers>
<customer firstname="Joe" lastname="Bloggs" description="Member of the Bloggs family"/>
<customer firstname="Joe" lastname="Soap" description="Member of the Soap family"/>
<customer firstname="Fred" lastname="Bloggs" description="Member of the Bloggs family"/>
<customer firstname="Jane" lastname="Bloggs" description="Is a member of the Bloggs family"/>
</customers>
</root>
How do I get, in pure XPath - not XSLT - an xpath expression that detects rows where lastname is the same, but has a different description? So it would pull the last node above?
How do I get, in pure XPath - not XSLT
- an xpath expression that detects rows where lastname is the same, but
has a different description?
Here's how to do this with a single XPath expression:
"/*/*/customer
[#lastname='Bloggs'
and
not(#description
= preceding-sibling::*[#lastname='Bloggs']/#description
)
]"
This expression selects all <customer> elements with attribute lastname equal to "Bloggs" and different value of the attribute description.
The selected nodes are:
<customer firstname="Joe" lastname="Bloggs" description="Member of the Bloggs family"/>
<customer firstname="Jane" lastname="Bloggs" description="Is a member of the Bloggs family"/>
/root/customers/customer[#lastname='Bloggs'
and not(#description = preceding-sibling::*[#lastname='Bloggs']/#description)
and not(#description = following-sibling::*[#lastname='Bloggs']/#description)]
It would perform better doing it in steps, though.

Resources