Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPATH: select subset of xml file

Tags:

java

xml

xslt

xpath

In my case, I have:

<booklist>
  <book id="1">
  </book>

  <book id="2">
  </book>

  <book id="3">
  </book>

  ......

</booklist>

How can i just return:

<booklist>
  <book id="1">
  </book>
</booklist>

if I use /booklist/book[@id=1], I can only get

<book id="1">
</book>

But I also need the document element. Thanks

like image 245
Ray Avatar asked Dec 22 '22 02:12

Ray


2 Answers

Rather than selecting the element that you do want, try excluding the elements that you don't want.

If you are just using XPATH, this will select all of the elements except for the book elements who's @id is not equal to 1 (i.e. <booklist><book id="1" /></booklist>).

//*[not(self::book[@id!='1'])]

If you want an XSLT solution, this stylesheet has an empty template that matches all of the <book> elements that do not have @id="1", which prevents them from being copied into the output.

Everything else (document node <booklist> and <book id="1">) will match the identity template, which copies forward.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!--Empty template to prevent book elements
        that do not have @id="1" from being
        copied into the output -->
    <xsl:template match="book[@id!='1']" />

    <!--identity template to copy all nodes and attributes to output -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
like image 130
Mads Hansen Avatar answered Dec 28 '22 11:12

Mads Hansen


How can i just return:

< booklist >
< book id=1 >
< /book >
< /booklist >

XPath is a query language. Evaluating an XPath expression cannot change the structure of the XML document.

This is why the answer is: No, with XPath this is not possible!

Whenever you want to transform an XML document (which is exactly the case here), the probably best solution is to use XSLT -- a language which was designed especially for processing and transforming tree-structured data.

Here is a very simple XSLT solution:

<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>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="book[not(@id=1)]"/>
</xsl:stylesheet>

When this transformation is applied to the provided XML file, the wanted, correct result is produced:

<booklist>
   <book id="1"/>
</booklist>
like image 28
Dimitre Novatchev Avatar answered Dec 28 '22 09:12

Dimitre Novatchev