Search code examples
c#xmlxslttagsfiltering

XSLT to create another XML by filtering only those node where tag value equals


I would like to create another XML with the help of XSLT from document sample below. The idea is to take all student where theirs Profile > City is [PNH], whatever their Origin > Address > City is. I knew with the help of XSLT, we can filter out, and copy only those we would like to have in the new XML document.

<?xml version="1.0" encoding="utf-8"?>
<Class>    
    <Student>
        <Profile>
            <Name>G1</Name>
            <City>PNH</City>            
            <RegDate>2020-06-20</RegDate>
        </Profile>
        <Origin>
            <Address>
                <City>REP</City>
            </Address> 
        </Origin>
    </Student>
    <Student>
        <Profile>
            <Name>G4</Name>
            <City>REP</City>            
            <RegDate>2020-06-20</RegDate>
        </Profile>
        <Origin>
            <Address>
                <City>PNH</City>
            </Address> 
        </Origin>
    </Student>    
    <Student>
        <Profile>
            <Name>G3</Name>
            <City>PNH</City>            
            <RegDate>2020-06-20</RegDate>
        </Profile>
        <Origin>
            <Address>
                <City>PNH</City>
            </Address> 
        </Origin>
    </Student>
    <Student>
        <Profile>
            <Name>G5</Name>
            <City>KOS</City>            
            <RegDate>2020-06-20</RegDate>
        </Profile>
        <Origin>
            <Address>
                <City>PNH</City>
            </Address> 
        </Origin>
    </Student>
</Class>

I would like to take only those student where Profile -> City equals 'PNH' which is final XML result should be

<?xml version="1.0" encoding="utf-8"?>
<Class>    
    <Student>
        <Profile>
            <Name>G1</Name>
            <City>PNH</City>            
            <RegisterDate>2020-06-20</RegisterDate>
        </Profile>
        <Origin>
            <Address>
                <City>REP</City>
            </Address> 
        </Origin>
    </Student>   
    <Student>
        <Profile>
            <Name>G3</Name>
            <City>PNH</City>            
            <RegisterDate>2020-06-20</RegisterDate>
        </Profile>
        <Origin>
            <Address>
                <City>PNH</City>
            </Address> 
        </Origin>
    </Student>
</Class>

I have tried this but it still get all student, but remove data in Profile Tag where City is not PNH

<xsl:template match="@*|node()">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
 </xsl:template>
 <xsl:template match="Profile[not(City = 'PNH')]"/>

Solution

  • If you want to exclude Students that satisfy a condition, then your template must match the Student element:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Student[not(Profile/City = 'PNH')]"/>
    
    </xsl:stylesheet>
    

    Alternatively, you could do simply:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="/Class">
        <xsl:copy>
            <xsl:copy-of select="Student[Profile/City = 'PNH']"/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>