首页 文章

xslt和xpath:匹配前面的注释

提问于
浏览
7

给出这个xml:

<root>
    <list>
        <!-- foo's comment -->
        <item name="foo" />
        <item name="bar" />
        <!-- another foo's comment -->
        <item name="another foo" />
    </list>
</root>

我想使用XPath来选择所有在它们之前有注释的项目节点,也就是说我喜欢选择“foo”和“另一个foo”项,而不是“bar”项 .

我已经摆弄了前兄弟轴和comment()函数,但无济于事 .

3 回答

  • 0

    这似乎有效:

    //comment()/following-sibling::*[1]/self::item
    

    它会立即寻找跟随兄弟的评论,这些评论也是 <item> 元素 . 我不知道更好的方式来表达丑陋的部分 . 请注意,如果它被写成 ::item[1] 那么它也会发现 <item> 没有立即被评论所取代 .

  • 3

    The currently selected solution

    //comment()/following-sibling::*[1]/self::item
    

    doesn't work 在注释和元素之间存在处理指令(或整组处理指令)的情况下 - 正如Martin Honnen的评论中所注意到的那样 .

    The solution below doesn't have such a problem .

    以下XPath表达式仅选择紧跟在注释节点之前的元素节点,或者紧接在仅有空白空间的文本节点之前,该节点前面紧跟注释节点:

    (//comment()
       /following-sibling::node()
         [1]
         [self::text()
        and 
         not(normalize-space())
         ]
          /following-sibling::node()
                 [1] [self::item]
     ) 
    |
    (//comment()
       /following-sibling::node()
         [1]
         [self::item]
     )
    

    Here is a complete test

    我们使用这个XML文档:

    <root>
        <list>
            <!-- foo's comment -->
            <item name="foo" />
            <item name="bar" />
            <!-- another foo's comment -->
            <item name="another foo" />
            <!-- comment 3 --><item name="immed.after 3"/>
            <!-- comment 4 --><?PI ?><item name="after PI"/>
        </list>
    </root>
    

    When the following transformation is applied on the above XML document

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
    
     <xsl:template match="/">
       <xsl:copy-of select=
        "
        (//comment()
           /following-sibling::node()
             [1]
             [self::text()
            and
             not(normalize-space())
             ]
              /following-sibling::node()
                     [1] [self::item]
         )
        |
        (//comment()
           /following-sibling::node()
             [1]
             [self::item]
         )
        "/>
     </xsl:template>
    </xsl:stylesheet>
    

    the wanted, correct result is produced

    <item name="foo"/>
    <item name="another foo"/>
    <item name="immed.after 3"/>
    
  • 3

    this thread中所述,引入测试( <xsl:if test="..."></xsl:if> ),如:

    前同辈::评论()

    只测试节点是否有前面的兄弟节点是评论 .

    如果你想知道,作为元素或评论的前面兄弟姐妹,最近的一个是评论,你可以尝试:

    (preceding-sibling::*|preceding-sibling::comment())[1][self::comment()] # WRONG
    

    但是:这不起作用,因为虽然“[1]”首先表示在前兄弟的向后方向,但这并不意味着对于带括号的表达式 - 它首先表示文档顺序

    你可以试试:

    (preceding-sibling::*|preceding-sibling::comment())[last()][self::comment()]
    

    要么

    preceding-sibling::node()[self::*|self::comment()][1][self::comment()]
    

    例如:

    <xsl:stylesheet version="2.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
      <xsl:output omit-xml-declaration="no" indent="no"/>
    
      <xsl:template match="//item">
        <xsl:if test="preceding-sibling::node()[self::*|self::comment()][1][self::comment()]">
          <xsl:value-of select="./@name" />
        </xsl:if>
      </xsl:template>
    </xsl:stylesheet>
    

    只会显示:

    foo
    another foo
    

    打字时:

    C:\Prog\xslt\preceding-sibling_comment>
      java -cp ..\saxonhe9-2-0-6j\saxon9he.jar net.sf.saxon.Transform -s:test.xml -xsl:t.xslt -o:res.xml
    

    有:

    • test.xml :您的问题中显示了您的文件

    • t.xslt :上面的xslt文件

    • res.xml :生成的转换文件


    编辑:因为它没有考虑处理指令,我把答案留给了社区维基 .

相关问题