如何在XSL中过滤?

时间:2017-02-22 23:13:01

标签: xml xslt xpath xslt-2.0

我正在学习XSLT并且正在尝试过滤现有的XML文件,并且基本上仅使用选定的感兴趣节点复制树 - 如果它们匹配条件,则说子字符串为'test'。

使用身份转换模式,我有以下代码段:

<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="(node() |  @*)[contains(name(.), 'test')]" />

<!-- Bonus Q: What would be happening behind the scenes when I put this code inside the copy element?
<xsl:value-of select="." /> -->

    </xsl:copy>
</xsl:template>

现在这让我得到以下输出,

<head>
<testA> <testAChild /></testA> <!-- should be <testA> <testAChild> foo </testAChild></testA> -->
<testB /> <!-- should be <testB> bar </testB> -->
<Ctest /> <!-- should be <Ctest> foobar </Ctest> -->
          <!-- should be <DontDeleteThis> <testD> 420 </testD></DontDeleteThis> -->
</head>

但是,它在结果树中没有值。此外,在当前节点为假但子女,孙子女或可能的大孩子可以通过标准时,不会检查每个案例。

以下是输入XML的示例:

<head>
    <testA>
        <testAChild> foo </testAChild>
    </testA>
    <testB> bar </testB>
    <Ctest> foobar </Ctest>
    <DeleteThis> DELETED </DeleteThis>
    <DontDeleteThis>
        <testD>  420 </testD>
    </DontDeleteThis>
</head>

2 个答案:

答案 0 :(得分:1)

使用此

    <xsl:template match="node()">
    <xsl:copy>
        <xsl:apply-templates select="node()[descendant-or-self::*[contains(name(.), 'test')]]" />
    </xsl:copy>
</xsl:template>

<xsl:template match="node()[contains(name(.), 'test')]">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

它会给你的欲望输出

答案 1 :(得分:1)

如果要匹配祖先元素名称,后代元素名称和后代处理指令名称,则必须明确地这样做。您的代码仅检查当前节点的名称。如果要匹配属性名称,则需要确保不能丢弃属性所附加的元素。例如:

<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0" xml:lang="en-latn">
    <output media-type="application/xml"/>
    <template match="attribute::node() | child::node()">
        <copy>
            <variable name="attributes" select="attribute::node()[contains(name(), 'test')]"/>
            <variable name="elements" select="child::*[count((descendant-or-self::node() | attribute::node())[contains(name(), 'test')]) > 0]"/>
            <variable name="comments" select="child::comment()[count(ancestor::node()[contains(name(), 'test')]) > 0]"/>
            <variable name="PIs" select="child::processing-instruction()[count(ancestor-or-self::node()[contains(name(), 'test')]) > 0]"/>
            <variable name="text" select="child::text()[count(ancestor::node()[contains(name(), 'test')]) > 0]"/>
            <apply-templates select="$attributes | $elements | $comments | $PIs | $text"/>
        </copy>
    </template>
</transform>

另外值得注意的是,Rupesh的代码与处理指令(PI)节点名称不匹配。 *node()之间存在细微差别; *是除attributenamespace轴之外的元素节点的简写,这意味着您必须使用node()来匹配PI节点。 (在XPath 2中,* / element()中有element(*)的相应缩写。我想知道这会让这个概念变得更加混乱。)

至于您的红利问题,value-of元素在所选节点上运行string XPath函数。因此,对于所有匹配的元素,元素的字符串值(即,其连接的所有文本节点)将在value-of元素的位置输出。对于匹配的属性,注释,处理指令和文本节点,不会输出其他文本,因为copy元素忽略了这些节点类型的内容。