给出这个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()函数,但无济于事。
答案 0 :(得分:3)
这似乎有效:
//comment()/following-sibling::*[1]/self::item
它会立即查找同时也是<item>
元素的评论兄弟。我不知道更好的方式表达::*[1]/self::item
部分,这是丑陋的;请注意,如果它是::item[1]
,那么它也会发现<item>
不会立即通过评论。
答案 1 :(得分:3)
当前选择的解决方案:
//comment()/following-sibling::*[1]/self::item
在评论和元素之间存在处理指令(或整组处理指令)的情况下,不起作用 - 正如Martin Honnen在评论中所注意到的那样。 / p>
以下解决方案没有这样的问题。
以下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]
)
这是一个完整的测试:
我们使用这个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>
对上述XML文档应用以下转换时:
<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>
产生了想要的正确结果:
<item name="foo"/>
<item name="another foo"/>
<item name="immed.after 3"/>
答案 2 :(得分:0)
正如this thread中所述,引入了一个测试(<xsl:if test="..."></xsl:if>
),如:
前同辈::评论()
只会测试节点是否前面的兄弟是评论。
如果你想知道,作为元素或评论的前面兄弟姐妹,最近的兄弟姐妹是否是评论,你可以尝试:
(preceding-sibling::*|preceding-sibling::comment())[1][self::comment()] # WRONG
但是:这不起作用,因为虽然“
[1]
”首先表示向后方向 对于preceding-sibling
,并不意味着对于带括号的表达式 - 它 首先按文件顺序排列
您可以尝试:
(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
:生成的转化文件编辑:由于它没有考虑处理说明,我把答案留给了社区维基。