这是一种方法来做你想做的事,使用一个<xsl:key>
,否则遵循你的方法二。
示例输入文件 (data.xml):
<?xml version="1.0" encoding="utf-8"?>
<input>
<data>001</data>
<data>002</data>
<data>005</data>
</input>
示例地图文件 (map.xml):
<?xml version="1.0" encoding="utf-8"?>
<map default="??">
<entry key="001">RZ</entry>
<entry key="002">TH</entry>
<entry key="003">SC</entry>
</map>
示例 XSL 样式表,解释如下:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:param name="map-file" select="string('map.xml')" />
<xsl:variable name="map-doc" select="document($map-file)" />
<xsl:variable name="default-value" select="$map-doc/map/@default" />
<xsl:key name="map" match="/map/entry" use="@key" />
<xsl:template match="/input">
<output>
<xsl:apply-templates select="data" />
</output>
</xsl:template>
<xsl:template match="data">
<xsl:variable name="raw-value" select="." />
<xsl:variable name="mapped-value">
<xsl:for-each select="$map-doc">
<xsl:value-of select="key('map', $raw-value)" />
</xsl:for-each>
</xsl:variable>
<data>
<xsl:choose>
<xsl:when test="$mapped-value = ''">
<xsl:value-of select="$default-value" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$mapped-value" />
</xsl:otherwise>
</xsl:choose>
</data>
</xsl:template>
</xsl:stylesheet>
这是做什么的:
- 用于
document()
打开map.xml
,将生成的节点集保存到变量中
- 保存默认值以供进一步参考
- 准备一个
<xsl:key>
针对“地图”节点集的工作
<xsl:for-each>
不作为循环使用,而是作为在调用key()
函数之前切换执行上下文的一种方式 - 否则key()
将针对“数据”文档起作用并且不返回任何内容
- 找到函数对应的节点
key()
,保存到变量中
- 检查输出上的变量值 - 如果它为空,则使用默认值
- 重复(通过
<xsl:apply-templates>
)
这个巧妙<xsl:for-each>
技巧的功劳归功于Jeni Tennison,他在 XSL 邮件列表中描述了该技术。请务必阅读主题。
针对 data.xml 运行样式表的输出:
<?xml version="1.0" encoding="utf-8"?>
<output>
<data>RZ</data>
<data>TH</data>
<data>??</data>
</output>
所有这些都是 XSLT 1.0。我确信存在一个更好/更优雅的版本,它利用了 XSLT 2.0 提供的优势,但不幸的是,我对 XSLT 2.0 并不太熟悉。也许其他人发布了更好的解决方案。
编辑
通过 Dimitre Novatchev 在评论中的提示,我能够创建一个相当短且更可取的样式表:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:param name="map-file" select="string('map.xml')" />
<xsl:variable name="map-doc" select="document($map-file)" />
<xsl:variable name="default" select="$map-doc/map/default[1]" />
<xsl:key name="map" match="/map/entry" use="@key" />
<xsl:template match="/input">
<output>
<xsl:apply-templates select="data" />
</output>
</xsl:template>
<xsl:template match="data">
<xsl:variable name="raw-value" select="." />
<data>
<xsl:for-each select="$map-doc">
<xsl:value-of select="(key('map', $raw-value)|$default)[1]" />
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>
但是,这需要一个稍微不同的映射文件才能在 XSLT 1.0 中工作:
<?xml version="1.0" encoding="utf-8"?>
<map>
<entry key="001">RZ</entry>
<entry key="002">TH</entry>
<entry key="003">SC</entry>
<!-- default entry must be last in document -->
<default>??</default>
</map>