-1

Suppose we have an xml tree:

<root>
<a>
 <b>
  <c>
   <d />
  </c>
 </b>
</a>
</root>

Desired output:

<root>
<a>
 <b>
  <c>
  </c>
 </b>
</a>
</root>

i.e. How can you select the entire xml tree without the <d /> node included?

Relevant question: XPath - Get node with no child of specific type

C.W.
  • 452
  • 1
  • 10
  • 15
  • 1
    If you are using XSLT, you should be able to achieve it in this way: https://stackoverflow.com/a/12152983/4206925 which copies the whole xsl excluding specific node. Plus, if you need to save it into a variable, try this: https://stackoverflow.com/a/11183356/4206925 – MewX Jul 06 '18 at 00:00
  • 1
    I can't see any possible reason for downvoting this question. Yes, it's been asked before (in different words, of course), yes, it shows a common misunderstanding of what XPath does, but neither of those are reasons for downvoting. It's a well formed question. – Michael Kay Jul 06 '18 at 08:35
  • 1
    XPath alone can't do what you are asking for. XPath is about isolating/finding parts of an XML document or document fragment. What you are describing is transforming the original XML (the source tree of nodes) into a different structure (the result tree of nodes). That is accomplished with XSLT (which will need some XPath expressions within it). – Scott Marcus Jul 06 '18 at 21:21

2 Answers2

1

XPath is for selection. Your desired output is not available to be selected from your input XML.

XSLT is for transformation. Your output XML can easily be transformed from your input XML via the identity transformation plus a template to suppress d elements:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- By default, copy nodes to output -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- But suppress d elements -->
  <xsl:template match="d"/>

</xsl:stylesheet>
kjhughes
  • 106,133
  • 27
  • 181
  • 240
-1

First select nodes of type d

.//*[d]

Then use that to select everything but d nodes

.//*[not(d)]
Brian Purgert
  • 159
  • 1
  • 3
  • Downvote explanation: This answer is wrong. `.//*[d]` does *not* select "nodes of type d". It selects descendent (or self) nodes from the current node that have `d` child elements. – kjhughes Aug 25 '20 at 16:51