0

我有一个小问题。我的 XML 中的一个节点可能包含一个整数,我必须用一个字符串替换这个整数。每个数字都与一个字符串匹配。

例如我有:


整数 - 字符串

1 - 待办事项

2 - 进行中

3 - 完成

4 - 错误

5 - 中止


原始 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>

我在问是否有另一种方法可以做到这一点。

4

7 回答 7

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 的版本及其繁琐的 document('') 调用是为 XSLT 1.0 设计的 - 如果您使用的是 2.0,它会简单得多。当人们不说他们使用的是什么版本时,我通常假设为 2.0,Dimitre 通常假设为 1.0。)

我越来越多地看到人们在使用 contains() 表示“=”时会犯错误。如果要测试节点的内容是否为“X”,请使用$node = "X",而不是contains($node, "X")

于 2012-08-31T18:51:04.997 回答
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"/>
于 2012-08-31T15:47:32.873 回答
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> 
于 2012-08-31T15:58:45.700 回答
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>
于 2012-08-31T15:36:53.970 回答
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>
于 2018-12-04T14:15:54.930 回答
-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>

除非您需要额外的复杂性,否则请保持简单。

于 2012-08-31T16:50:14.417 回答
-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>

请注意,“状态列表”中的值正好相隔 11 个字符(最长值的长度),因此子字符串中的 * 11 和 ,11 。因为你从 1 而不是 0 计数,所以你必须从索引中减去 1。或者,您可以在开始时用 11 个空格填充变量,而不是减去 1,这取决于您。该normalize-space调用只是从提取的值中去除多余的空格。

如果你想让它更整洁,你可以在每个值之间放置一个分隔符,并*12,11在该substring调用中使用。

如果您有大量可能的值,这不是一个可以很好地扩展的解决方案,并且显然它需要您可能的 id 处于一个序列中,但如果只有几个值,它就相当紧凑。

于 2012-08-31T18:07:27.153 回答