使用变量作为XPath选择的一部分

时间:2012-01-13 16:40:53

标签: variables xslt xpath

我希望将变量用作XPath表达式的一部分。

我的问题可能是msxsl节点集函数......不确定。但是不要让那个云你的判断......继续阅读...

我正在使用.NET函数来加载内容文件,该文件通过定制的XML内容传递。 @file会生成XML文件。

页面上的定制XML看起来像:

<control name="import" file="information.xml" node="r:container/r:group[@id='set01']/r:item[1]" />

XSL看起来像:

<xsl:variable name="document">
    <xsl:copy-of select="ext:getIncludedContent(@file)" />
</xsl:variable>

然后我将其转换为节点集,以便我可以查询文档

<xsl:variable name="preset-xml" select="msxsl:node-set($document)" />   

我加载的源文件如下:

<container>
    <group id="set01">
        <item>value01</item>
        <item>value02</item>
        <item>value03</item>
    </group>
    <group id="set02">
        <item>value04</item>
        <item>value05</item>
    </group>                    
</container>

直到这一点为止。我可以看到源文件通过并以XML格式输出。

当我尝试使用从内容中输入的XPath表达式查询源文件时,我的问题就出现了。

我试过了:

<xsl:value-of select="$preset-xml/@node" />

显然,这不起作用,因为它将@node视为XML加载的直接子项。

我试过了:

<xsl:variable name="node" select="@node" />
<xsl:value-of select="$preset-xml/$node" />

但它不喜欢第二个变量。

我尝试过concat($ preset-xml,'/',$ node),但仍然会在结果中绘制整个文档。

我现在唯一可以解决这个问题的方法就是在模板中写出完整的表达式:

<xsl:value-of select="$preset-xml/r:container/r:group[@id='set01']/r:item[1]" />

正确地带来了value01

但那是一个硬编码的解决方案。 我想开发一个可以从内容中操作的解决方案,以适应任何类型的导入内容,并在内容文件中声明参数。

P.S。我正在使用XSLT 1.0,因为技术管理员不会更改Microsoft解析器以支持更高版本的XSL,因此任何解决方案都需要在编写时考虑到这一点。

2 个答案:

答案 0 :(得分:0)

在XSLT中没有类似于反射的功能。特别是,MS XSLT引擎在加载XSLT时编译XPath查询,而不是在应用于XML文档时编译。这是有原因的:它将代码(XSLT)与数据(输入XML)分开。

你想通过混合代码和数据来实现什么;你确定你真的需要从输入XML执行任意XPath表达式吗?例如,考虑一下,如果用户传递的@name等于例如//*,然后您将输出整个输入XML文档的内容,该文档可能包含一些敏感数据。

如果你真的需要做你描述的事情,你可以编写自己的XSLT extension object,它将接受文档根和XPath查询,并将后者应用于前者。然后你就可以这样称呼它:

<xsl:value-of select="myExtensionNs:apply-xpath($preset-xml, @node)"/>

对于concat($preset-xml,'/',$node)的原始尝试,concat是字符串连接函数。您向它提供一些参数,并返回其字符串表示的串联。因此,concat($preset-xml,'/',$node)将返回$preset-xml的字符串值,与/连接,与$ node的字符串值连接。如果您尝试编写所需的XPath查询,concat('$preset-xml','/',$node)似乎更合乎逻辑(请注意引号);仍然,没有办法将结果字符串(例如$preset-xml/r:container/r:group[@id='set01']/r:item[1])评估为相应的XPath查询值;它只能发送到输出。

答案 1 :(得分:0)

一个可能的技巧是调用参数化的xsl:template,该参数执行关键的选择比较部分并将其输出作为字符串进行评估。

我有一个类似的问题(计算任意属性值的所有节点),这种方式已经解决(顺便说一句:$sd = 'document($filename)',所以我加载了辅助xml文件的内容):

<xsl:template match="/">
  <xsl:variable name="string_cntsuccess">
    <xsl:for-each select="./Testcase">
      <xsl:variable name="tcname" select="@location"/>
      <xsl:for-each select="$sd//TestCase[@state='Passed']">
        <xsl:call-template name="producedots">
          <xsl:with-param name="name" select="$tcname"/>
        </xsl:call-template>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="cntsuccess" select="string-length($string_cntsuccess)"/>
</xsl:template>

<xsl:template name="producedots">
  <xsl:param name="name"/>
  <xsl:variable name="ename" select="@name"/>
  <xsl:if test="$name = $ename">
    <xsl:text>.</xsl:text>
  </xsl:if>
</xsl:template>