1

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

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

$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>

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

提前感谢您的任何提示。

问候 Vlax

4

3 回答 3

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])]
于 2012-08-02T12:01:03.087 回答
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. 如果给定元素名称,我们添加一个附加谓词,true()仅当所选元素的祖先名称集合不包含$element_to_be_excluded.

  3. 如果$element_to_be_excluded包含一个或多个元素的序列,我们添加一个额外的谓词,true()仅当所选元素不是$element_to_be_excluded.

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

于 2012-08-02T12:02:37.097 回答
2

我总是会写<xsl:variable name="foo"><xsl:sequence select="someExpression"/></xsl:variable>as之类的东西<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>

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

于 2012-08-02T12:01:27.307 回答