Search code examples
xmlxslt-2.0

How to match xml attribute name by its value and display that element only from list of elements


I am new to xslt. I want to display only matched item(s) from xml list. using xslt transformation.

in this case I only want to display attribute with name of "one" and "two"

Thanks in advance.

xml code:

<myparent>
    <mychild>
        <mygrndchild name="a" parent="1" >                       
            <attribute name="one" value="1"/>
            <attribute name="two" value="1"/>
            <attribute name="three" value="1"/>
            <attribute name="four" value="0"/>            
        </mygrndchild>      
        <mygrndchild name="b" parent="1" >                       
            <attribute name="one2" value="2"/>
            <attribute name="two2" value="3"/>
            <attribute name="three2" value="4"/>
            <attribute name="four2" value="5"/>            
        </mygrndchild>
    </mychild>
</myparent>

xslt code:


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes"/>
    <!--suppresses attribute in list-->
    
<xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node() "/>
        </xsl:copy>
    </xsl:template>
    
     <xsl:template match="/parent">
        <xsl:copy>
            <xsl:apply-templates select="child"/>
        </xsl:copy>
     </xsl:template>


     <xsl:template match="/child">
        <xsl:copy>
            <xsl:apply-templates select="grandchild"/>
        </xsl:copy>
     </xsl:template>
     
     <xsl:template match="/grandchild">
        <xsl:copy>
            <xsl:apply-templates select="attribute"/>
        </xsl:copy>
     </xsl:template>

     <xsl:template match="/attribute">
        <xsl:copy>
            <xsl:apply-templates select="@*[. = 'one']"/>
        </xsl:copy>
     </xsl:template>

  <xsl:template match="/attribute">
        <xsl:copy>
            <xsl:apply-templates select="@*[. = 'two']"/>
        </xsl:copy>
     </xsl:template>

</xsl:stylesheet>

this code outputs xml as is.

expected results:

<myparent>
    <mychild>
        <mygrndchild name="a" parent="1" >                       
            <attribute name="one" value="1"/>           
        </mygrndchild>      
        <mygrndchild name="a" parent="1" > 
            <attribute name="two" value="1"/>   
        </mygrndchild>
    </mychild>
</myparent>

I appreciate your help in advance. this is for me learn some xml transformation.


Solution

  • I suspect you want something like

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="3.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="#all">
    
      <xsl:param name="att-list" as="xs:string*" select="'one', 'two'"/>
      
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="attribute[not(@name = $att-list)]"/>
    
    </xsl:stylesheet>
    

    Online fiddle using Saxon HE 12.

    If you are really using an XSLT 2 processor replace the xsl:mode declaration with the identity transformation template (the first one in your posted code).

    Or based on the wanted result, assuming XSLT 3, you could use

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="3.0"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="#all">
      
      <xsl:output indent="yes"/>
    
      <xsl:param name="att-list" as="xs:string*" select="'one', 'two'"/>
      
      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="mychild">
        <xsl:copy>
          <xsl:copy-of select="snapshot(.//attribute[@name = $att-list])/ancestor::mygrndchild"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Online fiddle using Saxon HE 12.