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:
Related
I'm trying to get with xPath the position only of the first element which has the attribute value true.
<?xml version="1.0" encoding="UTF-8"?>
<elements>
<element attribute="false"/>
<element attribute="true"/>
<element attribute="true"/>
</elements>
What I have so fare is:
head(/elements/element[#attribute='true']/position())
Result:
1
But it should be:
2
What am I doing wrong?
position() returns the position of the element in the nodelist created by the predicate, i.e. with the false excluded. Instead of position, you can e.g. count the number of preceding elemements.
For example, this works even in XPath 1.0:
1+count(/elements/element[#attribute="true"][1]/preceding-sibling::element)
I think it's (with XPath 3):
head(index-of(/elements/element/#attribute, 'true'))
saxon-lint --xpath 'count(//element[#attribute="true"]/position())' file.xml
From Michael answer:
saxon-lint --xpath 'head(index-of(/elements/element/#attribute, "true"))' file.xml
Output
2
I am trying to capture a value using XPath based on value of a different field.
Example XML:
<?xml version="1.0" encoding="UTF-8" ?>
<employees>
<employee>
<id>1</id>
<firstName>Tom</firstName>
<lastName>Cruise</lastName>
<photo>https://jsonformatter.org/img/tom-cruise.jpg</photo>
</employee>
<employee>
<id>2</id>
<firstName>Maria</firstName>
<lastName>Sharapova</lastName>
<photo>https://jsonformatter.org/img/Maria-Sharapova.jpg</photo>
</employee>
<employee>
<id>3</id>
<firstName>Robert</firstName>
<lastName>Downey Jr.</lastName>
<photo>https://jsonformatter.org/img/Robert-Downey-Jr.jpg</photo>
</employee>
</employees>
I am trying to get Xpath expression for value in the firstName field, when id value is 3.
You can locate parent node based on the known child node and then find the desired child node of that parent, as following:
//employee[./id='3']/firstName
the expression above will give the desired firstName node itself.
To retrieve it's text value this can be used:
//employee[./id='3']/firstName/text()
<category>
<Movi Name="Test">
<Price>$3.95</Price>
</Movi>
<Movi Name="test d">
<Price>$13.95</Price>
</Movi>
</category>
can anyone help on this XML to find movie greater than $11 with XPath
Given all prices are in the same currency and format, this bit of XPath does the job:
/category/Movi[number(substring(./Price/text(), 2)) > 11]
Just for the sake of completeness, another option is:
//Price[number(translate(text(), '$','')) > 11]
How to write a Xpath for two attributes? e.g. i need to get a value of discount > 20% and also the same discount is greater than amount 200(without any link to base value)
You can combine constraints in predicates. E.g.:
from lxml import etree
doc = etree.XML("""<xml>
<items>
<item discount_perc="25" discount_value="250">Something</item>
</items>
</xml>
""")
doc.xpath('items/item[#discount_perc > 20 and #discount_value > 200]')
Will try to answer by a simple example. Imagine you have the following xml:
<?xml version="1.0"?>
<data>
<node value="10" weight="1">foo</node>
<node value="10" weight="2">bar</node>
</data>
Then use this query to select the first <node>'s text:
//node[#value="10" and #weight="1"]/text()
and this for the second:
//node[#value="10" and #weight="2"]/text()
Hope this helps.
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.