Amelia K
Amelia K

Reputation: 71

Select Parent Node without Child node. XSLT

I would like to select Parent node without Child node.

Example:

<Shop>
    <Product>
       <ProductId>1</ProductId>
       <Description>ProductList</Description> 
       <Milk>
         <MilkId></MilkId>
       </Milk>
    </Product>
</Shop>

Desired Output:

<Shop>
    <Product>
       <ProductId>1</ProductId>
       <Description>ProductList</Description> 
    </Product>
</Shop>

I tried below XSLT but it failed to return correct result:

<xsl:copy-of select="//Product/not[Milk]"/>

Thank you for any help.

Update:

XSLT:

<xsl:copy-of select="Product/*[not(self::Milk)]" />

Returns:

<ProductId>1</ProductId>

I need below structure to be returned:

<Shop>
        <Product>
           <ProductId>1</ProductId>
           <Description>ProductList</Description> 
        </Product>
    </Shop>

Upvotes: 0

Views: 947

Answers (1)

zx485
zx485

Reputation: 29052

You can use a variant of the Identity template:

<!-- Identity template variant -->
<xsl:template match="node()|@*">
    <xsl:copy>
         <xsl:apply-templates select="node()[local-name()!='Milk']|@*" />
    </xsl:copy>
</xsl:template>

Or, as a more XSLT-2.0 way suggested in the comments

<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node() except Milk|@*" />
    </xsl:copy>
</xsl:template>

It copies all nodes except for the ones named Milk and its children.


If you want to apply this only to Product nodes, you also have to use the Identity template and change the matching rule to

<xsl:template match="Product">...

A solution using only xsl:copy-of could be copying the Product element and then copy all of its children (except for the Milk ones) with

<xsl:copy-of select="Product/*[not(self::Milk)]" />

Or, in a whole XSLT-2.0 template

<xsl:template match="//Product">
    <xsl:copy>
      <xsl:copy-of select="* except Milk" />
    </xsl:copy>
</xsl:template>

A whole XSLT-1.0 stylesheet could look like

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

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

    <xsl:template match="Product">
        <xsl:copy>
          <xsl:copy-of select="*[not(self::Milk)]" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Its output is:

<?xml version="1.0"?>
<Shop>
    <Product>
        <ProductId>1</ProductId>
        <Description>ProductList</Description>
    </Product>
</Shop>

Upvotes: 0

Related Questions