如何在 xsl:template 中匹配节点和子节点(同名)

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

我有一个 inkscape svg 文件。

简化版:

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

我想提取层 A(和 B)和 D。

这适用于直接位于根元素下方的层 A。

<?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>

但不复制D层

所以我的问题是:我怎样才能不仅匹配根目录下的节点,而且匹配另一个 "g" 元素下的节点。

而不是:

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

做:

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

否则你的下一个模板:

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

永远不会应用于 D 层。

完成改造:

<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">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/*">
    <xsl:copy>
     <xsl:copy-of select=".//svg:g[@inkscape:label='layerA' or @inkscape:label='layerD']"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

应用于提供的 XML(添加命名空间声明以使其格式正确)文档时:

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
    <g inkscape:label="layerA">
        <g inkscape:label="layerB"/></g>
    <g inkscape:label="layerC">
        <g inkscape:label="layerD"/></g>
</svg>

产生(我猜是)想要的正确结果:

<svg xmlns="http://www.w3.org/2000/svg" 
     xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
   <g inkscape:label="layerA">
      <g inkscape:label="layerB"/>
   </g>
   <g inkscape:label="layerD"/>
</svg>

再次感谢您的回答!

我只想添加一种替代方法来实现我的目标(在 svg 中导出包含图层子集的 png)。

https://github.com/wader/inkmake

inkfile 看起来像这样:

output.png input.svg -* +layerA +layerB +layerD

这让我省去了在将它们导出为 png 之前生成许多新 svg 文件的麻烦。

但是再次感谢。