tags:

views:

70

answers:

4

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

A: 

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 root element. Thanks

Ray
BTW, i have hundreds of books
Ray
+1  A: 

When you try to select a sub-element, only this will be returned.

FB55
+3  A: 

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"&gt;

    <!--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>
Mads Hansen
A: 

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"&gt;
 <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>
Dimitre Novatchev