我试图解决的问题是获取所有仅包含唯一文本元素的元素,但同时也能够根据作为参数传递给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>
现在的问题是,它有更优雅的方法来解决这个问题吗?
提前感谢任何提示。
此致 明经
答案 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)]
<强>解释强>:
取消了parent::*
。
如果给出了元素名称,只有当所选元素的祖先名称集不包含{{1}中包含的特定名称时,才会添加true()
的附加谓词。 }}
如果$element_to_be_excluded
包含一个或多个元素的序列,只有当所选元素不是{{1}中包含的元素之一时,我们才会添加另一个谓词$element_to_be_excluded
}}
请注意,在两种情况下都可以使用单个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>
(或者可能是一些更专业的匹配模式)。