Reputation: 1042
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
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
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
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