I have the following XML document :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE inventory SYSTEM "books.dtd">
<inventory>
<book num="b1">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<price>14.95</price>
<chapter>
<title>Snow Crash - Chapter A</title>
<paragraph>
This is the <emph>first</emph> paragraph.
<image file="firstParagraphImage.gif"/>
afetr image...
</paragraph>
<paragraph>
This is the <emph>second</emph> paragraph.
<image file="secondParagraphImage.gif"/>
afetr image...
</paragraph>
</chapter>
<chapter>
<title>Snow Crash - Chapter B</title>
<section>
<title>Chapter B - section 1</title>
<paragraph>
This is the <emph>first</emph> paragraph of section 1 in chapter B.
<image file="Chapter_B_firstParagraphImage.gif"/>
afetr image...
</paragraph>
<paragraph>
This is the <emph>second</emph> paragraph of section 1 in chapter B.
<image file="Chapter_B_secondParagraphImage.gif"/>
afetr image...
</paragraph>
</section>
</chapter>
<chapter>
<title>Chapter C</title>
<paragraph>
This chapter has no images and only one paragraph
</paragraph>
</chapter>
</book>
<book num="b2">
<title>Burning Tower</title>
<author>Larry Niven</author>
<author>Jerry Pournelle</author>
<publisher>Pocket</publisher>
<price>5.99</price>
<chapter>
<title>Burning Tower - Chapter A</title>
</chapter>
<chapter>
<title>Burning Tower - Chapter B</title>
<paragraph>
This is the <emph>second</emph> paragraph of chapter B in the 2nd book.
<image file="Burning_Tower_Chapter_B_secondParagraphImage.gif"/>
afetr image...
</paragraph>
</chapter>
</book>
<book num="b3">
<title>Zodiac</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<price>7.50</price>
<chapter>
<title>Zodiac - Chapter A</title>
</chapter>
</book>
<!-- more books... -->
</inventory>
How to write an XPath 1.0 expression to select all books that have more then 1 image?
I tried inventory/book//image[2]/ancestor::book
but it give wrong result ...
is inventory/book//image[2]
give all the 2nd image in every book ?
Use:
/*/book[(.//image)[2]]
This selects all book
elements that are children of the top element of the XML document and that have a second image
descendant.
This expression is evaluated potentially faster than any expression starting with //
, because an expression starting with //
typically causes the whole document to be traversed.
It is also more efficient than:
//book[count(.//image)>1]
even if this expression was re-written not to start with //
.
This is so, because in the above expression count(.//image)
causes all image
descendants to be counted, while in our solution:
(.//image)[2]
only verifies that a second image
descendant exists.
Finally, here is an XSLT - based verification:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy-of select="/*/book[(.//image)[2]]"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied to the provided XML document:
<inventory>
<book num="b1">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<price>14.95</price>
<chapter>
<title>Snow Crash - Chapter A</title>
<paragraph>
This is the <emph>first</emph> paragraph.
<image file="firstParagraphImage.gif"/>
afetr image...
</paragraph>
<paragraph>
This is the <emph>second</emph> paragraph.
<image file="secondParagraphImage.gif"/>
afetr image...
</paragraph>
</chapter>
<chapter>
<title>Snow Crash - Chapter B</title>
<section>
<title>Chapter B - section 1</title>
<paragraph>
This is the <emph>first</emph> paragraph of section 1 in chapter B.
<image file="Chapter_B_firstParagraphImage.gif"/>
afetr image...
</paragraph>
<paragraph>
This is the <emph>second</emph> paragraph of section 1 in chapter B.
<image file="Chapter_B_secondParagraphImage.gif"/>
afetr image...
</paragraph>
</section>
</chapter>
<chapter>
<title>Chapter C</title>
<paragraph>
This chapter has no images and only one paragraph
</paragraph>
</chapter>
</book>
<book num="b2">
<title>Burning Tower</title>
<author>Larry Niven</author>
<author>Jerry Pournelle</author>
<publisher>Pocket</publisher>
<price>5.99</price>
<chapter>
<title>Burning Tower - Chapter A</title>
</chapter>
<chapter>
<title>Burning Tower - Chapter B</title>
<paragraph>
This is the <emph>second</emph> paragraph of chapter B in the 2nd book.
<image file="Burning_Tower_Chapter_B_secondParagraphImage.gif"/>
afetr image...
</paragraph>
</chapter>
</book>
<book num="b3">
<title>Zodiac</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<price>7.50</price>
<chapter>
<title>Zodiac - Chapter A</title>
</chapter>
</book>
<!-- more books... -->
</inventory>
the XPath expression is evaluated and the selected nodes (in this case just one) are copied to the output:
<book num="b1">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<price>14.95</price>
<chapter>
<title>Snow Crash - Chapter A</title>
<paragraph>
This is the <emph>first</emph> paragraph.
<image file="firstParagraphImage.gif"/>
afetr image...
</paragraph>
<paragraph>
This is the <emph>second</emph> paragraph.
<image file="secondParagraphImage.gif"/>
afetr image...
</paragraph>
</chapter>
<chapter>
<title>Snow Crash - Chapter B</title>
<section>
<title>Chapter B - section 1</title>
<paragraph>
This is the <emph>first</emph> paragraph of section 1 in chapter B.
<image file="Chapter_B_firstParagraphImage.gif"/>
afetr image...
</paragraph>
<paragraph>
This is the <emph>second</emph> paragraph of section 1 in chapter B.
<image file="Chapter_B_secondParagraphImage.gif"/>
afetr image...
</paragraph>
</section>
</chapter>
<chapter>
<title>Chapter C</title>
<paragraph>
This chapter has no images and only one paragraph
</paragraph>
</chapter>
</book>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With