有很多类似的问题,但我无法找到答案。
想象一下,你有一个这样的HTML页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Page title</title>
</head>
<body>
<div id="content">
<table>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>D</td>
<td>E</td>
<td>F</td>
</tr>
</table>
</div>
</body>
</html>
并且您希望选择页面上第二个<td>
元素,该元素是其父的第一个子元素。在这种情况下,它是元素<td>D</td>
。
请注意,此措辞应保持不变,例如它与选择第二个<tr>
然后选择第一个子元素(产生相同元素)不同,因为我正在处理的原始页面是比这个最小的测试用例复杂得多,这种方法在那里不起作用。
到目前为止我做了什么:
CSS选择器 #content td:first-child
找到我A
和D
,现在我可以通过JS选择第二个元素(document.querySelectorAll("query")[1]
)或Java(我最终使用这些元素)。但是,使用附加代码来完成可以通过选择器完成的操作是非常不一致的。
同样,我可以使用 XPath表达式:id('content')//td[1]
。它相当于上面的CSS选择器。它返回一个节点集,所以我认为id('content')//td[1][2]
将按照我想要的方式工作,但没有运气。
过了一段时间,我发现( id('content')//td[1] )[2]
按照我想要的方式工作,所以我去了,我很满意。
尽管如此,看到我无法通过单个查询获取我的元素令我感到失望,因此出现了一个学术问题:是否有其他解决方案,无论是使用CSS选择器还是XPath表达式来做我的查询?我错过了什么?可以吗?
答案 0 :(得分:2)
CSS选择器当前没有提供任何方法来选择一组全局匹配元素中的第n个元素或整个DOM中某个元素的第n个出现。 Selectors 3和Selectors 4提供的结构:nth-*()
功能伪类都由其父级的第n个子项与条件匹配,而不是由整个DOM中的第n个元素计数
当前的Selectors语法没有提供直观的方式来说明“这是DOM中一组匹配元素的第n个”;选择器4中的偶数:nth-match()
和:nth-last-match()
的语法非常笨拙。所以这确实令人失望。
对于XPath,正如您已经找到的那样,要使用的表达式为(id('content')//td[1])[2]
。外部()
只是意味着“应该在[2]
谓词”之前评估整个子表达式,或者[2]
谓词应该对整个子表达式的结果进行操作,而不仅仅是{{1} }“。如果没有它们,表达式//td[1]
将被集体处理,两个冲突的谓词永远不会一起工作(你不能将相同的元素放在第一个和第二个!)。
在子表达式周围加括号不会使它成为额外的查询本身;如果是,那么您可以将td[1][2]
,id('content')
,//td
和[1]
中的每一个视为“查询”,并且隐含< / em>(或可选)括号。这是很多疑问:)
答案 1 :(得分:1)
使用这个简单的XPath表达式:
(//td[1])[2]
基于XSLT的验证:
<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="node()|@*">
<xsl:copy-of select="(//td[1])[2]"/>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Page title</title>
</head>
<body>
<div id="content">
<table>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>D</td>
<td>E</td>
<td>F</td>
</tr>
</table>
</div>
</body>
</html>
评估XPath表达式并将此评估结果复制到输出中:
<td>D</td>