说我的标记是:
<html>
<body>
<div>
<div>blbaba</div>
<p>a</p>
<p>b</p>
<p>c</p>
<p>d</p>
<div id="a1">blbaba</div>
<p>e</p>
<p>f</p>
<p>g</p>
<p>h</p>
<div>blbaba</div>
</div>
</body>
</html>
如何选择相对于特定元素的元素,即之前的n
个节点(在文档中可以是之前的父节点或兄弟节点)。
示例:
我想在div <p>
之前选择第二个@id ="a1"
元素,因此我的预期元素为<p>c</p>
答案 0 :(得分:3)
preceding::
和ancestor::
轴不相交,因此在一般情况下,您将无法选择所需元素,除非您使用所选元素通过这两个轴。
引用 W3C XPath 1.0 Specification :
•前一轴包含与文档相同的所有节点 在文档顺序中的上下文节点之前的上下文节点, 排除任何祖先并排除属性节点和命名空间 节点
使用强>:
(//p[@id='a1']/ancestor::div | //p[@id='a1']/preceding::div)
[last() -$n +1]
这将选择属于div
元素div
元素的前一个和祖先p
元素的并集的第n个id
元素(按文档顺序向后) } attribute的值是字符串&#34; a1
&#34;。这里我们假设id
属性唯一地标识它所属的元素。
例如,如果我们有这个XML文档(我使示例更加真实,因为div
可以嵌套,而p
不能):
<html>
<body>
<div>
<p>a</p>
<p>b</p>
<p>c</p>
<div id="y">
<p>d</p>
<div>blbaba</div>
<p id="a1">e</p>
<p>f</p>
<p>g</p>
<p>h</p>
<div>blbaba</div>
</div>
</div>
</body>
</html>
我们希望在div
p
&#34; id
&#34;之前(以文档顺序)获得第二个a1
, 然后此XPath表达式选择所需的div
元素:
(//p[@id='a1']/ancestor::div | //p[@id='a1']/preceding::div)
[last() -1]
这个简短的XSLT转换证明上面的XPath表达式精确地选择了想要的div
元素(通过评估XPath表达式并复制整个选定的div
元素):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select=
"(//p[@id='a1']/ancestor::div | //p[@id='a1']/preceding::div)
[last() -1]"/>
</xsl:template>
</xsl:stylesheet>
当上述转换应用于上述源XML文档时,它会选择所需的div
元素并将其复制到输出:
<div id="y">
<p>d</p>
<div>blbaba</div>
<p id="a1">e</p>
<p>f</p>
<p>g</p>
<p>h</p>
<div>blbaba</div>
</div>
答案 1 :(得分:0)
两者都不能在Chrome中工作(例如),你可以先检查它是否有兄弟,如果它是null,那么通过第二个XPath获得祖先。
对or
的此行为的解释是here。
<html><head><script>
function doTest() {
testElement('a1');
testElement('a2');
}
function testElement(id) {
var ancestor = getPath("//div[@id='" + id +"']/ancestor::*[2]");
alert('ancestor ' + ancestor);
var sibling = getPath("//div[@id='" + id + "']/preceding-sibling::*[2]");
alert('sibling ' + sibling);
var both = getPath("//div[@id='" + id + "']/preceding-sibling::*[2]|//div[@id='" + id +"']/ancestor::*[2]");
alert('both ' + both);
}
function getPath(path) {
return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
</script></head>
<body onload='doTest()'>
<div>
<div id='a1'>blbaba</div>
<p>a</p>
<p>b</p>
<p id='me'>c</p>
<p>d</p>
<div id="a2">blbaba</div>
<p>e</p>
<p>f</p>
<p>g</p>
<p>h</p>
<div>blbaba</div>
</div>
</body>