user2020692
user2020692

Reputation: 53

How To Get Certain Parent Element Node When Child Condition Found

I'm having problems writing a C# script that'll get me a certain parent element of a given child element. To clear things up, this is an example of the XML tree.

<parent attribute='X'>
  <child_element1>A</child_element1>
  <child_element2 attribute='Y'>
    <grandchild_element1>B</grandchild_element1>
    <grandchild_element2>
      <key>C</key>
    </grandchild_element2>
    <grandchild_element3>D</grandchild_element3>
  </child_element2>
  <child_element3>E</child_element3>
</parent>  

Traversing the tree, my script has found the <key> node. What I'm trying to produce is the following tree.

<parent attribute='X'>
  <child_element2 attribute='Y'>
    <grandchild_element1>B</grandchild_element1>
    <grandchild_element2>
      <key>C</key>
    </grandchild_element2>
    <grandchild_element3>D</grandchild_element3>
  </child_element2>
</parent>  

As you can see, I'm trying to remove child_element1 and child_element3 in original tree.

I've written a pseudo-code for the script as follows, but so far have failed to figure out how to script the real thing in C#.

  1. Show all the first and second parent elements above of the key node. grandchild_element2 is first parent of key and child_element2 is second parent of key. So all their elements are shown.
  2. Show only node/element that has immediate relation with key for next parent level. parent is third parent of key. The parent element that has direct relation with key is child_element2. So only child_element2 is shown. child_Element1 and child_element2 are not shown because they do not have direct relation with the key

I've taken a look at the following solutions on stackoverflow, but unfortunately they all only show how to get all parent elements (instead of showing the ones which are ancestors of the <key> node.

  1. Retrieve XML parent node attribute if child node meets a certain criteria and assign both to variables
  2. C# XML, find node and all his parents

Upvotes: 1

Views: 948

Answers (1)

JLRishe
JLRishe

Reputation: 101652

This is quite easy if you use an XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:param name="valueToFind" select="'C'" omit-xml-declaration="yes" />

  <xsl:template match="/*">
    <xsl:apply-templates select="node()[descendant-or-self::node() = $valueToFind]" />
  </xsl:template>

  <xsl:template match="*">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates 
            select="node()[descendant-or-self::node() = $valueToFind]" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

When the example XML is given a single root element and fed into this XSLT, the result is:

<a>
  <a.1 name="First">
    <a.1.2>
      <a.1.2.2>
        <key>C</key>
      </a.1.2.2>
    </a.1.2>
  </a.1>
</a>

In case you're unfamiliar with XSLT, an XSLT parameter:

<xsl:param name="valueToFind" select="'C'" />

is essentially a variable whose value you can pass in from the executing code. Here, I've just given it it the default value C, so it can be run in an XSLT debugger and produce a demonstrable result.

Upvotes: 1

Related Questions