Reputation: 73
I have a XML-document like this:
<food>
<fruit>
<apple>
<product>
<title>Apple 1</title>
<price>7</price>
</product>
<product>
<title>Apple 2</title>
<price>4</price>
</product>
</apple>
<grapes>
<product>
<title>Red grapes </title>
<price>4</price>
</product>
<product>
<title>Green grapes</title>
<price>6</price>
</product>
</grapes>
</fruit>
<drink>
<water>
<product>
<title>Water 1</title>
<price>1</price>
</product>
<product>
<title>Water 2</title>
<price>6</price>
</product>
</water>
<soda>
<product>
<title>Coca-Cola</title>
<price>10</price>
</product>
<product>
<title>Sprite</title>
<price>4</price>
</product>
</soda>
</drink>
</food>
I have an XML structure like this.
I want to pick up the product name and price of all products that cost above 5. How do I write an XPath expression that does this?
Upvotes: 1
Views: 4522
Reputation: 243459
Use:
/*/*/*/product[price > 5]/title
|
/*/*/*/product/price[. > 5]
This selects the union of:
All title
elements that have a product
parent whose price
child's string value when treated as a number is greater than 5 that is a great-grandson of the top element of the XML document.
All price
elements whose string value when treated as a number is greater than 5, and whose parent is a product
that is a great-grandson of the top element of the XML document.
The elements selected are provided in a node-set (typically) in document order, which means that a title
and its corresponding price
are next to each other in whatever collection of nodes is produced by the corresponding XPath API.
In XSLT one would use a very simple transformation like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="product[price > 5]">
Name: <xsl:value-of select="title"/>
<xsl:text>, price </xsl:text>
<xsl:value-of select="price"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the provided XML document:
<food>
<fruit>
<apple>
<product>
<title>Apple 1</title>
<price>7</price>
</product>
<product>
<title>Apple 2</title>
<price>4</price>
</product>
</apple>
<grapes>
<product>
<title>Red grapes </title>
<price>4</price>
</product>
<product>
<title>Green grapes</title>
<price>6</price>
</product>
</grapes>
</fruit>
<drink>
<water>
<product>
<title>Water 1</title>
<price>1</price>
</product>
<product>
<title>Water 2</title>
<price>6</price>
</product>
</water>
<soda>
<product>
<title>Coca-Cola</title>
<price>10</price>
</product>
<product>
<title>Sprite</title>
<price>4</price>
</product>
</soda>
</drink>
</food>
the wanted, correct result is produced:
Name: Apple 1, price 7
Name: Green grapes, price 6
Name: Water 2, price 6
Name: Coca-Cola, price 10
It is even better to specify the price limit as a global parameter that is externally passed to the transformation.
In this case an XSLT 2.0 transformation is a bit simpler:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pLimit" select="5"/>
<xsl:template match="product[price > $pLimit]">
Name: <xsl:value-of select="title"/>
<xsl:text>, price </xsl:text>
<xsl:value-of select="price"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
A corresponding XSLT 1.0 transformation is:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pLimit" select="5"/>
<xsl:template match="product">
<xsl:if test="price > $pLimit">
Name: <xsl:value-of select="title"/>
<xsl:text>, price </xsl:text>
<xsl:value-of select="price"/>
</xsl:if>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Upvotes: 2
Reputation: 1646
I suppose that your document ends with </food>
. Is that what you want ?
//product[price > 5]
EDIT:
If you do not want the <product>
tag, you can do that :
//product[price > 5]/*
However, I find this last solution less convenient, since we do not delimit the products any more.
Upvotes: 3