给出以下XML文档:
<document>
<a>123</a>
<foo_1>true</foo_1>
<foo_2>false</foo_2>
<foo_3>true</foo_3>
<foo_4>true</foo_4>
<foo_5>false</foo_5>
<b/>
<bar_1>false</bar_1>
<bar_2>false</bar_2>
<bar_3>true</bar_3>
<bar_4>false</bar_4>
<bar_5>true</bar_5>
<c>some text</c>
</document>
我希望通过删除包含false
的所有枚举元素并将包含true
的所有枚举元素转换为<prefix_n>value</prefix_n>
形式来转换此文档,其中value
是数字在下划线之后。
对于上面给出的示例,结果应如下所示:
<document>
<a>123</a>
<foo_n>1</foo_n>
<foo_n>3</foo_n>
<foo_n>4</foo_n>
<b/>
<bar_n>3</bar_n>
<bar_n>5</bar_n>
<c>some text</c>
</document>
为此,我使用以下转换,工作正常。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<!-- standard copy template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[substring(name(), 1, 4) = 'foo_']">
<xsl:if test=". = 1 or . = 'true'">
<xsl:element name="foo_n">
<xsl:value-of select="substring-after(name(), 'foo_')"/>
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:template match="*[substring(name(), 1, 4) = 'bar_']">
<xsl:if test=". = 1 or . = 'true'">
<xsl:element name="bar_n">
<xsl:value-of select="substring-after(name(), 'bar_')"/>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
现在我面临的问题是我必须处理多种不同的前缀,而不仅仅是foo_
和bar_
。
有没有办法将模板规则转换为命名模板,我可以将前缀作为参数传递,从而避免编写大量重复的模板规则?
答案 0 :(得分:2)
这是你可以看到它的一种方式:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(name(), 'foo_') or starts-with(name(), 'bar_')]">
<xsl:if test=". = 1 or . = 'true'">
<xsl:element name="{substring-before(name(), '_')}-n">
<xsl:value-of select="substring-after(name(), '_')"/>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
这是另一个:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[contains(translate(name(), '123456789', '000000000'), '_0')]">
<xsl:if test=". = 1 or . = 'true'">
<xsl:variable name="prefix" select="substring-before(translate(name(), '123456789', '000000000'), '_0')" />
<xsl:element name="{$prefix}-n">
<xsl:value-of select="substring(name(), string-length($prefix) + 2)"/>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
最后一个应该使用任何前缀后跟_[1-9]
- 包括包含额外下划线的前缀,并包含包含其他前缀的前缀。
答案 1 :(得分:0)
有没有办法将模板规则转换为命名模板,我可以将前缀作为参数传递
嗯,当然可以:
<xsl:template name="if-true">
<xsl:param name="prefix"/>
<xsl:if test=". = 1 or . = 'true'">
<xsl:element name="{concat($prefix, 'n')}">
<xsl:value-of select="substring-after(name(), $prefix)"/>
</xsl:element>
</xsl:if>
</xsl:template>
<!-- example using the above: -->
<xsl:template match="*[starts-with(name(), 'foo_')]">
<xsl:call-template name="if-true">
<xsl:with-param name="prefix" select="'foo_'"/>
</xsl:call-template>
</xsl:template>
但目前尚不清楚这是否真的能实现你的目标:
,从而避免编写大量重复的模板规则?
因为您仍然需要一堆第二种模板来匹配您想要转换的特定元素。 @ michael.hor257k提出的解决方案建议,通过使相同的模板匹配您想要转换的所有元素来避免重复,是一个更好的选择。