这是一种按照您的意愿行事的方法,使用<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 在 cmets 中的提示,我能够创建一个相当短且更可取的样式表:
<?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>