qazplm 4ever
qazplm 4ever

Reputation: 45

Select node without a particular child

For example I have an XML sample like this

<a>
    <a1>A1</a1>
        <a11>A11</a11>
    <a2>A2</a2>
    Text <strong>text</strong> text...
<a>

How can I use XPath to select node a contain only

<a>
    <a2>A2</a2>
    Text <strong>text</strong> text...
<a>

Upvotes: 1

Views: 1457

Answers (3)

Daniel Haley
Daniel Haley

Reputation: 52848

This xpath:

//a[normalize-space(.)='A2 Text text text...']

Would only select:

<a>
    <a2>A2</a2>
    Text <strong>text</strong> text...
</a>

XSLT Example...

XML Input

<doc>
  <a>
    <a1>A1</a1>
    <a11>A11</a11>
    <a2>A2</a2>
    Text <strong>text</strong> text...
  </a>
  <a>
    <a2>A2</a2>
    Text <strong>text</strong> text...
  </a>  
</doc>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <xsl:copy-of select="//a[normalize-space(.)='A2 Text text text...']"/>
  </xsl:template>

</xsl:stylesheet>

XML Output

  <a>
   <a2>A2</a2>
    Text <strong>text</strong> text...
  </a>

Upvotes: 0

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

XPath is a query language for XML documents. This means that an XPath expression can only select a set of nodes and/or extract data.

Remember: An XPath expression can never cause modufication of the structure of an XML document (such as deleting a node).

The answer is that no XPath expression is going to select the node you want because there isn't such a node in the XML document.

What you want can easily be accomplished with XSLT and (not so easily) with XQuery:

<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="*[starts-with(name(), 'a1')]"/>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<a>
    <a1>A1</a1>
    <a11>A11</a11>
    <a2>A2</a2>     Text 
    <strong>text</strong> text... 
</a>

the wanted, correct result is produced:

<a>
   <a2>A2</a2>     Text 
    <strong>text</strong> text... 
</a>

Upvotes: 1

Mark J Miller
Mark J Miller

Reputation: 4871

Not sure if this is flexible enough for you, but it should get you started

/a/a1 | a/text() | /a/*[not(starts-with(name(), 'a'))]

You can play around with it easily here: http://www.xpathtester.com/test

Upvotes: 1

Related Questions