artsince
artsince

Reputation: 1042

XPath exlude node and its descendants

I have an XML like this:

<Root xmlns:test1="http://www.test1.com" xmlns:test2="http://www.test2.com" Attr="root">
  <test1:Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">
    <child11 Attribute11="c11">Element11</child11>
  </test1:Child1>
  <test2:Child2 Attribute2="c2">
    <child21 Attribute21="c21">
        <child211 />
        <child212 />
        <child213 />
    </child21>
    <child22 Attribute22="c22">Element22</child22>
  </test2:Child2>
  <test2:Child3 Attribute3="c3">
    <child31>Element31</child31>
  </test2:Child3>
</Root>

I would like to write an XPath so that I will get to select all except for the child21 element and its descendants. So that the output should look like the following:

<Root xmlns:test1="http://www.test1.com" xmlns:test2="http://www.test2.com" Attr="root">
  <test1:Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">
    <child11 Attribute11="c11">Element11</child11>
  </test1:Child1>
  <test2:Child2 Attribute2="c2">
    <child22 Attribute22="c22">Element22</child22>
  </test2:Child2>
  <test2:Child3 Attribute3="c3">
    <child31>Element31</child31>
  </test2:Child3>
</Root>

what is the xpath code for this?

thanks a lot

Upvotes: 0

Views: 108

Answers (3)

MiMo
MiMo

Reputation: 11983

A XPath would select nodes, but if you wanty to actually copy the XML skipping certain elements what you need is an XSLT - this will produce the output you want:

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

  <!-- Template to copy everything-->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Template to skip 'child21' elements -->
  <xsl:template match="child21">
  </xsl:template>

</xsl:stylesheet>

Upvotes: 0

David Carlisle
David Carlisle

Reputation: 5652

XPath never modifies the nodes it selects, it just selects, them. If your selection includes (say) the Root element then when serialised it will include all the elements of your input document, even if you only select that single element.

You can iterate over all elements that dont have child21 in their ancestor-or-self axis by going

//*[not(ancestor-or-self::child21)]

But that isn't very useful if you want to generate the result shown.

It's trivial to filter out that element and its descendants with xslt, just have an identity template and add a single template

<xsl:template match="child21"/>

that discards that branch of the input, but you can't do that with XPath alone.

Upvotes: 1

Siva Charan
Siva Charan

Reputation: 18064

XPath to exclude child21

/Root/*/*[not(local-name()='child21')]

This gives the result as

child11
child22
child31

Modify this according to your requirement.

Upvotes: 0

Related Questions