如何在XSLT中动态选择节点

时间:2009-04-22 10:09:58

标签: xslt

我有一个XML文件:

<?xml version="1.0" standalone="yes"?>
<Questionnaire>
  <Temp_GridTypeTable_6>
    <Column2>Select Yes/No</Column2>
  </Temp_GridTypeTable_6>
  <Temp_GridTypeTable_1>
    <Column2>Rank 1,2,3</Column2>
  </Temp_GridTypeTable_1>
  <Temp_GridTypeTable_1>
    <Column1>I needed the income</Column1>
    <Column2>Why did you take a job on this project?</Column2>
  </Temp_GridTypeTable_1>
  <Temp_GridTypeTable_1>
    <Column1>Other</Column1>
    <Column2></Column2>
  </Temp_GridTypeTable_1>
  <Temp_GridTypeTable_2>
    <Column2>Select "Yes/No"</Column2>
  </Temp_GridTypeTable_2>
  <Temp_GridTypeTable_2>
    <Column1>No jobs</Column1>
    <Column2>344</Column2>
  </Temp_GridTypeTable_2>
  <Temp_GridTypeTable_3>
    <Column2>Input</Column2>
  </Temp_GridTypeTable_3>
  <Temp_GridTypeTable_3>
    <Column1>Unit</Column1>
    <Column2>123</Column2>
  </Temp_GridTypeTable_3>
</Questionnaire> 

我想访问

<xsl:for-each select="Questionnaire/concat('Temp_GridTypeTablenode_',"1"))>

但这句话不起作用。

3 个答案:

答案 0 :(得分:11)

这是如何不使用XML的一个例子。 “Temp_GridTypeTable”和“Column”数字是数据,而不是结构,它们不应包含在元素名称中。所以为什么你不使用不那么痛苦的东西,比如说:

<Questionnaire>
  <Temp_GridTypeTable type="6">
    <Column num="2">Select Yes/No</Column>
  </Temp_GridTypeTable>
  <Temp_GridTypeTable type="1">
    <!-- ... -->
  <Temp_GridTypeTable>
  <!-- ... -->
</Questionnaire>

话虽如此,对于你目前的情况,这是必要的:

<xsl:for-each select="Questionnaire/*[
  local-name()
  =
  concat('Temp_GridTypeTable_', '1')
]">

对于输入的“较少痛苦”版本,这是必需的:

<xsl:for-each select="Questionnaire/Temp_GridTypeTable[@type = 1]">

尽管第二个表达式更简单,更直接,但它的表现也会好得多。如果您可以提供帮助,我建议您更改输入XML。


编辑:继续在评论中展开自己的论点,我试着强调local-name()name() XPath函数之间的区别,以及差异的重要性:

                            | XML has namespaces  |  XML has no namespaces
----------------------------+---------------------+-----------------------
I care about namespaces     | use `name()`        |  use either function
                            |                     |
don't care about namespaces | use `local-name()`  |  use either function

通常:如果你属于“不关心命名空间”组(大多数XML新手或临时XML用户都这样做),那么只使用local-name()就可以了(有时甚至是有益的)。但是,当您获得的结果和您期望的结果开始分歧时,请准备好了解XML命名空间。此时您不再属于该组。

如果您属于“我关心命名空间”组,您无论如何都不需要此建议。 ; - )

答案 1 :(得分:2)

使用:

<强> Questionnaire/*[name() = concat('', $vSuffix)]

变量$vSuffix包含静态未知字符串 - 在本例中为“1”。

在Tomalak的答案中使用local-name()是不必要的长且不精确的,因为在一般情况下它允许具有各种(可能不需要的和意外的)名称的元素被选中,例如:

  • OhMy:Temp_GridTypeTable_1
  • Different:Temp_GridTypeTable_1
  • UnWanted:Temp_GridTypeTable_1

答案 2 :(得分:1)

您无法在运行时使用纯XSLT将字符串计算为XPath表达式。

您需要一个可以在运行时评估xpath表达式的扩展函数。例如,请参阅EXSLT project

在我的系统上,使用xsltproc,我可以完成你想要的任务:

<!-- load the saxon extensions -->
<xsl:stylesheet version="1.0" xmlns:xx="http://icl.com/saxon" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
...
<xsl:for-each 
    select="xx:evaluate(concat('Questionnaire/Temp_GridTypeTable_', '1'))">

在这里,我使用saxon扩展库中的evaluate函数。 EXSLT的评估函数应该以相同的方式工作。

XSLT处理器/库必须内置某种evaluate函数。请参阅库的文档。