这是XML:
<svg xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<text id="b376">
<tspan x="59" y="156" font-size="13px" font-family="Arial">80</tspan>
</text>
<use xlink:href="#b376" fill="#000000"/>
<text id="b374">
<tspan x="59" y="204" font-size="13px" font-family="Arial">60</tspan>
</text>
<use xlink:href="#b374" fill="#000000"/>
<defs>testDef</defs>
</g>
</svg>
这是我的XSL输入:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="g">
<g>
<xsl:apply-templates select="use|defs"/>
<defs>
<xsl:apply-templates select="*[name() != 'use' and name() != 'defs']"/>
</defs>
</g>
</xsl:template>
</xsl:stylesheet>
我想将所有节点包装在defs标签中除了使用标签和defs标签。因此,2个文本节点将包含在defs标签中,但defs和use不会。
这是我得到的
<?xml version="1.0"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<use xlink:href="#b376" fill="#000000"/>
<use xlink:href="#b374" fill="#000000"/>
<defs>testDef</defs>
<defs>
<text id="b376">
<tspan x="59" y="156" font-size="13px" font-family="Arial">80</tspan>
</text>
<text id="b374">
<tspan x="59" y="204" font-size="13px" font-family="Arial">60</tspan>
</text>
</defs>
</g>
</svg>
这就是我想要的:
<?xml version="1.0"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<use xlink:href="#b376" fill="#000000"/>
<use xlink:href="#b374" fill="#000000"/>
<defs>testDef</defs>
<defs>
<text id="b376">
<tspan x="59" y="156" font-size="13px" font-family="Arial">80</tspan>
</text>
</defs>
<defs>
<text id="b374">
<tspan x="59" y="204" font-size="13px" font-family="Arial">60</tspan>
</text>
</defs>
</g>
</svg>
我正在使用@TessellatingHeckler's comment在线工具进行测试。谢谢!
答案 0 :(得分:1)
您的当前输出(其中所有<text>
元素都包含在单个<defs>
标记中)正是我对读取您的XSL代码所期望的 - 对于每个<g>
,您有一个<defs>
,其中您处理的所有元素都不是<use>
或<defs>
:
<xsl:template match="g">
<g>
<xsl:apply-templates select="use|defs"/>
<!-- This part here: -->
<defs>
<xsl:apply-templates select="*[name() != 'use' and name() != 'defs']"/>
</defs>
</g>
</xsl:template>
由于<xsl:apply-templates select="*[name() != 'use' and name() != 'defs']"/>
,所以非<defs>
和非{{1}的文字use
,全部在单个文字refs
元素中,元素作为批处理。
您显然希望每个非<defs>
和非use
元素都包含在自己的defs
中。在这种情况下,您需要将文字<defs>
移动到 中与非<defs>
和非use
元素匹配的单独模板。
快速而肮脏的重构可能如下所示:
defs
请注意,此方法还会将原始<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- We don't really need a specific template for <g>, so
we let the identity template handle that case. -->
<!-- The only case where we need to define a different flow is
for children of <g> elements, that aren't <use> or <defs>. -->
<xsl:template match="*[name(..) = 'g'][name() != 'use' and name() != 'defs']">
<!-- The template matches _each_ such element, so if we
put the literal `<defs>` here, we get that `<defs>` as
a wrapper for _each_ such element. -->
<defs>
<xsl:copy-of select="."/>
</defs>
</xsl:template>
</xsl:stylesheet>
和<use>
元素保留在<defs>
父级中的相同位置。
答案 1 :(得分:1)
您的预期输出显示元素的顺序 对你很重要。
您需要第一个 use
和defs
代码,并且只需
所有剩余的元素,每个元素都包含在自己的defs
中
元件。
为了实现这一点,请使用以下脚本:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="g">
<g>
<xsl:apply-templates select="use|defs"/>
<xsl:for-each select="*[name() != 'use' and name() != 'defs']">
<defs>
<xsl:apply-templates select="."/>
</defs>
</xsl:for-each>
</g>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>
</xsl:stylesheet>
如您所见,我添加了for-each
循环select
从您的示例复制的属性。
此循环的内容:
defs
元素