我有点问题。 我的XML中的节点可能包含整数,我必须用字符串替换这个整数。 每个数字都与一个字符串匹配。
例如我有:
整数 - 字符串
1 - TODO
2 - 进展中
3 - 完成
4 - 错误
5 - ABORTED
原始XML:
<root>
<status>1</status>
</root>
转换后的XML:
<root>
<status>TODO</status>
</root>
所以我想用“TODO”代替1,用“IN PROGRESS”代替2 ......
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root/status">
<root>
<status>
<xsl:variable name="text" select="." />
<xsl:choose>
<xsl:when test="contains($text, '1')">
<xsl:value-of select="'TODO'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</status></root>
</xsl:template>
</xsl:stylesheet>
我在问是否有另一种方法可以做到这一点。
答案 0 :(得分:3)
有很多方法可以做到这一点。如果翻译来自1到N范围内的连续整数,我会使用
<xsl:variable name="index" select="xs:integer(status)"/>
<xsl:value-of select="('TODO', 'IN PROGRESS', 'DONE', 'ERROR', 'ABORTED')[$index]"/>
在有少量值的其他情况下,我可能会使用模板规则:
<xsl:template match="status[.='1']" mode="lookup">TODO</xsl:template>
<xsl:template match="status[.='2']" mode="lookup">IN PROGRESS</xsl:template>
等
在其他情况下,查找表是有意义的(请注意,Dimitre的版本及其繁琐的文档('')调用是针对XSLT 1.0设计的 - 如果您使用的是2.0,则相当简单。当人们不说他们的版本时正在使用我通常假设2.0和Dimitre通常假定为1.0。)
我越来越多地看到人们犯了“=”时使用contains()的错误。如果要测试节点的内容是否为“X”,请使用$node = "X"
,而不是contains($node, "X")
。
答案 1 :(得分:2)
实现此目的的一种方法是创建一种“查找”值表。这可以嵌入XSLT中,也可以放在单独的文件中。例如,如果将它放在XSLT文件中,它看起来就像这样..
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:lookup="lookup">
<lookup:data>
<status code="1">TO DO</status>
<status code="2">IN PROGRESS</status>
<status code="3">DONE</status>
</lookup:data>
然后,您还将创建一个变量来访问此数据
<xsl:variable name="lookup" select="document('')/*/lookup:data"/>
最后,要查找该值,您只需执行此操作
<xsl:value-of select="$lookup/status[@code = '1']/>
在这种情况下,这是完整的XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:lookup="lookup">
<xsl:output method="xml" indent="yes"/>
<lookup:data>
<status code="1">TO DO</status>
<status code="2">IN PROGRESS</status>
<status code="3">DONE</status>
</lookup:data>
<xsl:variable name="lookup" select="document('')/*/lookup:data"/>
<xsl:template match="status/text()">
<xsl:value-of select="$lookup/status[@code = current()]" />
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当应用于您的示例XML时,输出以下内容
<root>
<status>TODO</status>
</root>
将这些文件放在单独的文件中可能会更好,因为它们可以在其他样式表中重复使用。为此,只需创建一个名为“lookup.xml”的文件,然后添加XML
<data>
<status code="1">TO DO</status>
<status code="2">IN PROGRESS</status>
<status code="3">DONE</status>
</data>
注意,在这种情况下,您不需要名称空间。然后只需将变量的定义更改为以下
<xsl:variable name="lookup" select="document('lookup.xml')/data"/>
答案 2 :(得分:1)
您的解决方案中有许多不必要的代码。以下是一个简化版本,其工作方式相同:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root/status">
<root>
<status>
<xsl:choose>
<xsl:when test="contains(.,'1')">TODO</xsl:when>
<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
</xsl:choose>
</status>
</root>
</xsl:template>
</xsl:stylesheet>
答案 3 :(得分:0)
最简单的方法是从身份转换开始,然后添加特殊情况:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="status[. = '1']">
<status>TODO</status>
</xsl:template>
<!-- likewise for status[. = '2'] etc. -->
<!-- copy everything else -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 4 :(得分:0)
对于 XSLT 3.0版,您可以使用map
类型:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="MyMap" select="
map {
'1' : 'TODO',
'2' : 'IN PROGRESS',
'3' : 'DONE',
'4' : 'ERROR',
'5' : 'ABORTED'}">
</xsl:variable>
<xsl:template match="/root/status">
<status>
<xsl:variable name="text" select="."/>
<xsl:value-of select="$MyMap( $text )"/>
</status>
</xsl:template>
</xsl:stylesheet>
答案 5 :(得分:-1)
我的话。 XSLT并不容易,我认为不应该通过炫耀你对其他答案中所显示的内部工作的了解来使它变得更加困难。
为了方便你敲击头部,使用选择声明。我可能会把它拉成一个单独的模板(我在其他语言中使用这些方法)只是为了简化测试并帮助清理你的代码以便于阅读。
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="PrintStatus">
<!-- param we can pass a value into or default to the current node -->
<xsl:param name="text" select="." />
<xsl:choose>
<xsl:when test="contains($text, '1')">
<xsl:value-of select="'TODO'"/>
</xsl:when>
<!-- Assume your others go here -->
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/root/status">
<root>
<status>
<xsl:call-template name="PrintStatus" />
</status>
</root>
</xsl:template>
</xsl:stylesheet>
除非您需要额外的并发症,否则请保持简单。
答案 6 :(得分:-1)
我有时会在这种情况下使用的技巧是在一个字符串中使用值列表,并采用子字符串,如下所示:
<xsl:variable name="statuslist">TODO IN PROGRESSDONE ERROR ABORTED </xsl:variable>
<xsl:template match="status/text()">
<xsl:value-of select="normalize-space(substring($statuslist, ( . - 1 ) * 11 , 11))" />
</xsl:template>
注意,'statuslist'中的值恰好相隔11个字符(最长值的长度),因此子字符串中的* 11和11。因为从1开始计数而不是0,所以必须从索引中减去1。或者你可以在开头用11个空格填充变量而不是减去1,这取决于你。 normalize-space
调用只是从提取的值中删除多余的空格。
如果您想让它更整洁,可以在每个值之间放置一个分隔符,并在*12,11
调用中使用substring
。
如果你有大量可能的值,这不是一个可以很好地扩展的解决方案,显然它需要你的可能的id在一个序列中,但是如果只有几个值它就相当紧凑。