Search code examples
xslt

Only transform tags if child node exists


I have an XML file:

 <body>
     <trans-unit id="Id a" maxwidth="240" size-unit="char">
                <source> original a </source>
                <target>my target value </target>
     </trans-unit>
     <trans-unit id="Id b" maxwidth="240" size-unit="char">
                <source>original b</source>
     </trans-unit>
 </body>

I would like to identity transform the entire document, but only where I have a parent node 'trans-unit' that has a target tag, and one output where I do not:

output 1:

 <body>
     <trans-unit id="Id a" maxwidth="240" size-unit="char">
                <source> original a </source>
                <target>my target value </target>
     </trans-unit>
 </body>

output 2:

 <body>
     <trans-unit id="Id b" maxwidth="240" size-unit="char">
                <source>original b</source>
     </trans-unit>
 </body>

I have looked into identity transformation, but I can't get it to work to either block or include the entire parent node.


Solution

  • For output #1 you can do:

    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/body">
        <xsl:copy>
            <xsl:copy-of select="trans-unit[target]"/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    For output #2:

    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/body">
        <xsl:copy>
            <xsl:copy-of select="trans-unit[not(target)]"/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    You can combine both in a single stylesheet with two separate xsl:result-document instructions (or one principal result and one secondary result).