XSLT - 将文本节点的值解释为XPath查询(并在转换中使用它)

时间:2011-09-06 14:29:34

标签: xml xslt xpath

我一直在尝试为此提出一个不错的解决方案,但我甚至找不到一个不雅的解决方案。

我有一个看起来像这样的XML文件:

<Root>
    <Something>
        <SomethingElse>Value of SomethingElse</SomethingElse>
    </Something>

...

    <Map>
        <Node>
            <Path>/Root/Something/SomethingElse</Path>
        </Node>
    <Map>

...

</Root>

我想要做的是编写一个XSL转换,它将采用<Path>元素并将其text()值用作XPath查询,以将转换应用于<SomethingElse>元素,从而产生例如:

<text>Value of SomethingElse</text>

突然出现在我脑海中的第一件事就是:

<xsl:template match="Path">
    <text><xsl:value-of select="{text()}"/></text>
</xsl:template>

但这当然不起作用,因为select不是值属性。

我不知道如何解决这个问题。 Google搜索仅返回有关如何使用XPath获取文本值的结果,而不是相反。

我还想对返回的<SomethingElse>元素应用进一步的转换,但是一旦我弄清楚如何执行此操作,这应该是一块蛋糕。

非常感谢这一切, Slampisko

2 个答案:

答案 0 :(得分:2)

使用纯XSLT 1.0甚至2.0,您需要使用两个样式表,第一个接受输入并使用您想要使用的XPath表达式创建第二个样式表,然后针对原始输入运行第二个样式表。

或者您需要检查您的XSLT处理器是否支持扩展函数来将字符串计算为路径表达式,例如Saxon与http://www.saxonica.com/documentation/extensions/functions/evaluate.xml或AltovaXML之类的altova:evaluate函数http://manual.altova.com/AltovaXML/altovaxmlcommunity/index.html?xextaltova_general.htm

答案 1 :(得分:2)

虽然完整的动态XPath评估不是XSLT 1.0 / XPath 1.0或XSLT 2.0 / XPath 2.0的一部分,但是可以生成一种XSLT 1.0实现,它可以以相当有限的方式工作

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="text()"/>

 <xsl:template match="Path" name="eval">
  <xsl:param name="pPath" select="."/>
  <xsl:param name="pContext" select="/"/>

  <xsl:choose>
   <!-- If there is something to evaluate -->
   <xsl:when test="string-length($pPath) >0">
      <xsl:variable name="vPath" select=
          "substring($pPath,2)"/>

      <xsl:variable name="vNameTest">
       <xsl:choose>
        <xsl:when test="not(contains($vPath, '/'))">
         <xsl:value-of select="$vPath"/>
        </xsl:when>
        <xsl:otherwise>
         <xsl:value-of select=
             "substring-before($vPath, '/')"/>
        </xsl:otherwise>
       </xsl:choose>
      </xsl:variable>

      <xsl:call-template name="eval">
       <xsl:with-param name="pPath" select=
         "substring-after($pPath, $vNameTest)"/>
       <xsl:with-param name="pContext" select=
        "$pContext/*[name()=$vNameTest]"/>
      </xsl:call-template>
  </xsl:when>
  <!-- Otherwise we have evaluated completely the path -->
  <xsl:otherwise>
   <xsl:copy-of select="$pContext"/>
  </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<Root>
    <Something>
        <SomethingElse>Value of SomethingElse</SomethingElse>
    </Something>

...

    <Map>
        <Node>
            <Path>/Root/Something/SomethingElse</Path>
        </Node>
    </Map>

...

</Root>

产生了想要的正确结果

<SomethingElse>Value of SomethingElse</SomethingElse>

我们假设以下限制

  1. 我们评估的每个XPath表达式都必须由一系列名称测试组成,由XPath'/'运算符分隔 - 也就是说,每个位置步骤只指定一个元素名称。

    < / LI>
  2. 任何位置步骤都不能包含轴或谓词。