如何根据变量或参数查找元素是否具有祖先(XPath 2.0)

时间:2012-08-02 10:23:39

标签: xslt xpath xslt-2.0 xpath-2.0

我试图解决的问题是获取所有仅包含唯一文本元素的元素,但同时也能够根据作为参数传递给XSLT工作表的元素名称排除节点树。 / p>

选择仅包含非空的唯一文本元素的所有节点的部分相对容易:

$StartNode//element()/text()[normalize-space(.)]/parent::*

其中$StartNode是XML文档中特定元素的Xpath表达式。

现在我的部分遇到了一些问题,从结果中排除了特定的节点树:

所以我希望有类似的东西:

$StartNode//element()/text()[normalize-space(.)]/parent::*[not(ancestor::**$element_to_be_excluded**)]

其中$ element_to_be_excluded是要排除的元素名称。

但是不可能在表达式的那一部分使用变量......

所以我提出了这个解决方案

<xsl:variable name="ancestors_of_current_node" as="xs:string*">
   <xsl:sequence select="$current_parent_node/ancestor::*/name()"/>
</xsl:variable>
<xsl:variable name="is_value_in_sequence" as="xs:boolean" select="functx:is-value-in-sequence($exclude_node_local_name, $ancestors_of_current_node)"/>
<xsl:if test="not($is_value_in_sequence)">
    <xsl:call-template name="dataElementMap">
       <xsl:with-param name="node_item" select="$current_parent_node"/>
    </xsl:call-template>
</xsl:if>

其中functx:is-value-in-sequence是:

<xsl:function name="functx:is-value-in-sequence" as="xs:boolean" xmlns:functx="http://www.functx.com">
  <xsl:param name="value" as="xs:anyAtomicType?"/>
  <xsl:param name="seq" as="xs:anyAtomicType*"/>
  <xsl:sequence select="$value = $seq"/>
</xsl:function>

现在的问题是,它有更优雅的方法来解决这个问题吗?

提前感谢任何提示。

此致 明经

3 个答案:

答案 0 :(得分:3)

而不是做(由于变量而无效,如你所说)

$StartNode//element()/text()[normalize-space(.)]
   /parent::*[not(ancestor::$element_to_be_excluded)]

你可以试试这个,检查一下祖先的名字吗?

$StartNode//element()/text()[normalize-space(.)]
   /parent::*[not(ancestor::*[local-name() = $element_to_be_excluded])]

答案 1 :(得分:3)

如果$element_to_be_excluded只是元素的名称,请使用

$StartNode//element()
             [text()[normalize-space(.)]]
                [not(ancestor::*/name() = $element_to_be_excluded)]

如果$element_to_be_excluded是一个或多个元素的序列,请使用

$StartNode//element()
             [text()[normalize-space(.)]]
                [not(ancestor::* intersect $element_to_be_excluded)]

<强>解释

  1. 取消了parent::*

  2. 如果给出了元素名称,只有当所选元素的祖先名称集不包含{{1}中包含的特定名称时,才会添加true()的附加谓词。 }}

  3. 如果$element_to_be_excluded包含一个或多个元素的序列,只有当所选元素不是{{1}中包含的元素之一时,我们才会添加另一个谓词$element_to_be_excluded }}

  4. 请注意,在两种情况下都可以使用单个XPath表达式来选择所需的元素 - 根本不需要使用任何XSLT指令。

答案 2 :(得分:2)

我总是将<xsl:variable name="foo"><xsl:sequence select="someExpression"/></xsl:variable>之类的内容写为<xsl:variable name="foo" select="someExpression"/>。我不擅长在没有看到输入样本的情况下提出建议,但我怀疑不是使用命名模板而是使用这两个变量而xsl:if包装call-template代码可以使用模板中的模板编写例如

<xsl:apply-templates select=".[not(ancestor::*[local-name() eq $exclude_node_local_name])]" mode="m1"/>

将您的命名模板dataElementMap替换为例如

<xsl:template match="*" mode="m1">...</xsl:template>

(或者可能是一些更专业的匹配模式)。