Search code examples
xsltsvglayerinkscape

how to match nodes AND child nodes (same name) in xsl:template


I have an inkscape svg file.

simplified version:

<svg>
    <g inkscape:label="layerA">
        <g inkscape:label="layerB"/>
    </g>
    <g inkscape:label="layerC">
        <g inkscape:label="layerD"/>
    </g>
</svg>

I want to extract the layers A (and B) and D.

This works for layer A which is directly under the root element.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
>

<!-- Auto intend -->
<xsl:output indent="yes"/>

<!-- Copy every other node, element, attribute -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<!-- Do not copy any other group -->
<xsl:template match="svg:g"/>

<!-- Copy all matching groups -->
<xsl:template match="svg:g[@inkscape:label='layerA']|svg:g[@inkscape:label='layerD']">
    <xsl:copy-of select="."/>
</xsl:template>

But it does not copy layer D.

So my question is: How can I match not only the nodes directly under root, but under another "g" element.


Solution

  • Instead of :

    <!-- Do not copy any other group -->
    <xsl:template match="svg:g"/>
    

    do:

    <xsl:template match="svg:g">
        <xsl:apply-templates select="svg:g"/>
    </xsl:template>
    

    Otherwise your next template:

    <!-- Copy all matching groups -->
    <xsl:template match="svg:g[@inkscape:label='layerA']|svg:g[@inkscape:label='layerD']">
        <xsl:copy-of select="."/>
    </xsl:template>
    

    will never be applied to layer D.