在XSL中使用Map来扩展缩写

时间:2012-05-09 17:36:07

标签: xslt xslt-1.0 exslt

我在制作地图时看到了类似的问题。

答案有这段代码:

<xsl:stylesheet version="1.0" 
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:template match="/">
    <xsl:variable name="map">
        <map>
            <entry key="key-1">value1</entry>
            <entry key="key-2">value2</entry>
            <entry key="key-3">value3</entry>
        </map>
    </xsl:variable>
    <output>
        <xsl:value-of select="msxsl:node-set($map)/map/entry[@key='key-1']"/>
    </output>
</xsl:template>

我想替换输出命令以使用我的XML中的值来查看它是否是地图中的键,然后将其替换为值。

是在地图上进行for-each选择并与contains进行比较的最佳方法吗?

以下是XML的摘录:

<document>
   <content name="PART_DESC_SHORT" type="text" vse-streams="2" u="22" action="cluster" weight="1">
   SCREW - ADJUST
   </content>
</document>

内容节点值可能包含一个字符串,其中包含我想要用完整值替换的缩写。

谢谢, 保罗

1 个答案:

答案 0 :(得分:2)

无需使用for-each - 此XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">

  <xsl:output indent="yes" method="xml" />

  <xsl:variable name="abbreviations">
    <abbreviation key="Brkt Pivot R">Bracket Pivot R</abbreviation>
    <abbreviation key="Foo">Expanded Foo</abbreviation>
    <abbreviation key="Bar">Expanded Bar</abbreviation>
  </xsl:variable>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:variable name="text" select="."/>
    <xsl:variable name="abbreviation" select="msxsl:node-set($abbreviations)/*[@key=$text]"/>
    <xsl:choose>
      <xsl:when test="$abbreviation">
        <xsl:value-of select="$abbreviation"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

将转换精确副本中的任何XML,扩展所有匹配顶部abbreviations变量中定义的缩写的文本。

如果您只想在特定元素中展开缩写,可以修改第二个模板match="..."规则。

另一方面,如果你想扩展文本中所有缩写的任何出现,你需要循环 - 这意味着在XSLT中递归:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">

  <xsl:output indent="yes" method="xml" />

  <xsl:variable name="abbreviations">
    <abbreviation key="Brkt">Bracket</abbreviation>
    <abbreviation key="As">Assembly</abbreviation>
    <abbreviation key="Foo">Expanded Foo</abbreviation>
    <abbreviation key="Bar">Expanded Bar</abbreviation>
  </xsl:variable>

  <!-- Replaces all occurrences of a string with another within a text -->
  <xsl:template name="replace">
    <xsl:param name="text"/>
    <xsl:param name="from"/>
    <xsl:param name="to"/>
    <xsl:choose>
      <xsl:when test="contains($text,$from)">
        <xsl:value-of select="concat(substring-before($text,$from),$to)"/>
        <xsl:call-template name="replace">
          <xsl:with-param name="text" select="substring-after($text,$from)"/>
          <xsl:with-param name="from" select="$from"/>
          <xsl:with-param name="to" select="$to"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Replace all occurences of a list of abbreviation with their expanded version -->
  <xsl:template name="replaceAbbreviations">
    <xsl:param name="text"/>
    <xsl:param name="abbreviations"/>
    <xsl:choose>
      <xsl:when test="count($abbreviations)>0">
        <xsl:call-template name="replaceAbbreviations">
          <xsl:with-param name="text">
            <xsl:call-template name="replace">
              <xsl:with-param name="text" select="$text"/>
              <xsl:with-param name="from" select="$abbreviations[1]/@key"/>
              <xsl:with-param name="to" select="$abbreviations[1]"/>
            </xsl:call-template>
          </xsl:with-param>
          <xsl:with-param name="abbreviations" select="$abbreviations[position()>1]"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:call-template name="replaceAbbreviations">
      <xsl:with-param name="text" select="."/>
      <xsl:with-param name="abbreviations" select="msxsl:node-set($abbreviations)/*"/>
    </xsl:call-template>
  </xsl:template>

</xsl:stylesheet>

将第二个XSLT应用于

<document>
  <content name="PART_DESC_SHORT" type="text" vse-streams="2" u="22" action="cluster" weight="1">
    Brkt Pivot R
  </content>
</document>

产生

<document>
  <content name="PART_DESC_SHORT" type="text" vse-streams="2" u="22" action="cluster" weight="1">
    Bracket Pivot R
  </content>
</document>

请注意:

  • 此解决方案假定没有缩写ovelap(例如两个单独的缩写BrkBrkt

  • 它使用XSLT 1.0 - 使用XSLT 2.0可能有更好的解决方案

  • 这种繁重的字符串处理在XSLT中可能效率很低,用其他语言编写扩展函数并从XSLT调用它可能更好。