Jsoup :has() 选择器没有按预期工作
Jsoup :has() selector not working as expected
我正在尝试解析包含具有以下结构的多个单元格的 HTML table:
<td id="topic1234">
<a name='1234'></a>
<b><a href='/url'>Title</a><b>
<span class='s'>Details</span>
</td>
<td id="topic2345">
<a name='2345'></a>
<b><a href='/url'>Title</a><b>
<span class='s'>Details</span>
</td>
...
'id'属性,'a'元素带有'href'属性,'span'元素是重要的细节,两个元素直接嵌套。
我尝试使用
select("[id^=topic]"
+ ":has(> b > a[href])"
+ ":has(> span.s)")
但结果列表为空。当我将其更改为:
时它起作用了
select("td[id^=topic]"
+ ":has(td > b > a[href])"
+ ":has(td > span.s)")
但我不希望选择器依赖于根元素是 'td' 这一事实,并且根据文档判断,前者也应该有效。以下也不起作用:
select("[id^=topic]"
+ ":has(:root > b > a[href])"
+ ":has(:root > span.s)")
我是不是做错了什么?顺便用Jsoup 1.8.3
:has(selector)
中的选择器包含父元素。我不认为 >b
是 JSoup 中的有效选择器,但 *>b
应该没问题,它允许任何父元素。所以这应该有效:
select("[id^=topic]"
+ ":has(* > b > a[href])"
+ ":has(* > span.s)")
Edit1 回应评论:
为了使 :has(selector)
的选择器更有可能是 [id^=topic]
的直接子代,您还可以这样做:
select("[id^=topic]"
+ ":has([id^=topic] > b > a[href])"
+ ":has([id^=topic] > span.s)")
这当然仍然不能保证,因为父级的内部子级也可能带有一个以 topic
.
开头的 id
编辑2
与 类似,您可以通过将选择器分成两部分来确保。首先,我们匹配 ID 以 topic 开头的所有元素。然后我们循环这些并构造一个包含特定 id 的新选择器。只要所有元素的 id 都是独立的,这就可以工作。
String html = "<table><tr><td id=\"topic1234\">" +
"<a name='1234'></a>" +
"<div><b><a href='/url'>Title</a></b></div>" +
"<span class='s'>Details</span></td>\n" +
"<td id=\"topic2345\">\n" +
" <a name='2345'></a>\n" +
" <b><a href='/url'>Title</a></b>\n" +
" <span class='s'>Details</span>\n" +
"</td>"+
"<td id=\"topic3456\">\n" +
" <div id=\"topic4567\"><a name='3456'></a>\n" +
" <b><a href='/url'>Title</a></b>\n" +
" <span class='s'>Details</span>\n" +
" </div>" +
"</td></tr></table>";
Document doc = Jsoup.parse(html);
Elements selected = doc.select("[id^=topic]");
for (Element elem : selected) {
String idStr = elem.attr("id");
Element el = elem.select(":has(#"+idStr+" > b > a[href]):has(#"+idStr+" > span.s)").first();
if (el != null){
System.out.println("found matching element: "+el);
}
if (el != null){
System.out.println("does not really match: "+el);
}
}
我认为不可能为您的需要编写一个选择器,因为 JSoup 不支持像 :has(> tag)
.
这样的语法
不过,我认为您可以将选择器分成多个部分:
String html = "<table><td id=\"topic1234\">" +
"<a name='1234'></a>" +
"<div><b><a href='/url'>Title</a></b></div>" +
"<span class='s'>Details</span></td>\n" +
"<td id=\"topic2345\">\n" +
" <a name='2345'></a>\n" +
" <b><a href='/url'>Title</a></b>\n" +
" <span class='s'>Details</span>\n" +
"</td></table>"
Document doc = Jsoup.parse(html);
Elements selected = doc.select("[id^=topic]");
for (Element elem : selected) {
// Check if "b > a[href]" is a direct child of "td"
if (elem.select(":root > b > a[href]").size() > 0) {
System.out.println("Found: "+elem);
} else {
System.out.println("Not found:"+elem);
}
}
即html 代码如下:
<table>
<td id="topic1234">
<a name="1234"></a>
<div>
<b><a href="/url">Title</a></b>
</div>
<span class="s">Details</span></td>
<!-- second line -->
<td id="topic2345">
<a name="2345"></a>
<b><a href="/url">Title</a></b>
<span class="s">Details</span>
</td>
</table>
哪个returns:
Not found:<td id="topic1234"><a name="1234"></a>
<div>
<b><a href="/url">Title</a></b>
</div><span class="s">Details</span></td>
Found: <td id="topic2345"> <a name="2345"></a> <b><a href="/url">Title</a></b> <span class="s">Details</span> </td>
显然同样适用于第二个条件(即 span.s
)
请注意,在这种情况下,:root
选择器有效,因为 elem
的根元素是 td
而不是 table
我正在尝试解析包含具有以下结构的多个单元格的 HTML table:
<td id="topic1234">
<a name='1234'></a>
<b><a href='/url'>Title</a><b>
<span class='s'>Details</span>
</td>
<td id="topic2345">
<a name='2345'></a>
<b><a href='/url'>Title</a><b>
<span class='s'>Details</span>
</td>
...
'id'属性,'a'元素带有'href'属性,'span'元素是重要的细节,两个元素直接嵌套。 我尝试使用
select("[id^=topic]"
+ ":has(> b > a[href])"
+ ":has(> span.s)")
但结果列表为空。当我将其更改为:
时它起作用了select("td[id^=topic]"
+ ":has(td > b > a[href])"
+ ":has(td > span.s)")
但我不希望选择器依赖于根元素是 'td' 这一事实,并且根据文档判断,前者也应该有效。以下也不起作用:
select("[id^=topic]"
+ ":has(:root > b > a[href])"
+ ":has(:root > span.s)")
我是不是做错了什么?顺便用Jsoup 1.8.3
:has(selector)
中的选择器包含父元素。我不认为 >b
是 JSoup 中的有效选择器,但 *>b
应该没问题,它允许任何父元素。所以这应该有效:
select("[id^=topic]"
+ ":has(* > b > a[href])"
+ ":has(* > span.s)")
Edit1 回应评论:
为了使 :has(selector)
的选择器更有可能是 [id^=topic]
的直接子代,您还可以这样做:
select("[id^=topic]"
+ ":has([id^=topic] > b > a[href])"
+ ":has([id^=topic] > span.s)")
这当然仍然不能保证,因为父级的内部子级也可能带有一个以 topic
.
编辑2
与
String html = "<table><tr><td id=\"topic1234\">" +
"<a name='1234'></a>" +
"<div><b><a href='/url'>Title</a></b></div>" +
"<span class='s'>Details</span></td>\n" +
"<td id=\"topic2345\">\n" +
" <a name='2345'></a>\n" +
" <b><a href='/url'>Title</a></b>\n" +
" <span class='s'>Details</span>\n" +
"</td>"+
"<td id=\"topic3456\">\n" +
" <div id=\"topic4567\"><a name='3456'></a>\n" +
" <b><a href='/url'>Title</a></b>\n" +
" <span class='s'>Details</span>\n" +
" </div>" +
"</td></tr></table>";
Document doc = Jsoup.parse(html);
Elements selected = doc.select("[id^=topic]");
for (Element elem : selected) {
String idStr = elem.attr("id");
Element el = elem.select(":has(#"+idStr+" > b > a[href]):has(#"+idStr+" > span.s)").first();
if (el != null){
System.out.println("found matching element: "+el);
}
if (el != null){
System.out.println("does not really match: "+el);
}
}
我认为不可能为您的需要编写一个选择器,因为 JSoup 不支持像 :has(> tag)
.
不过,我认为您可以将选择器分成多个部分:
String html = "<table><td id=\"topic1234\">" +
"<a name='1234'></a>" +
"<div><b><a href='/url'>Title</a></b></div>" +
"<span class='s'>Details</span></td>\n" +
"<td id=\"topic2345\">\n" +
" <a name='2345'></a>\n" +
" <b><a href='/url'>Title</a></b>\n" +
" <span class='s'>Details</span>\n" +
"</td></table>"
Document doc = Jsoup.parse(html);
Elements selected = doc.select("[id^=topic]");
for (Element elem : selected) {
// Check if "b > a[href]" is a direct child of "td"
if (elem.select(":root > b > a[href]").size() > 0) {
System.out.println("Found: "+elem);
} else {
System.out.println("Not found:"+elem);
}
}
即html 代码如下:
<table>
<td id="topic1234">
<a name="1234"></a>
<div>
<b><a href="/url">Title</a></b>
</div>
<span class="s">Details</span></td>
<!-- second line -->
<td id="topic2345">
<a name="2345"></a>
<b><a href="/url">Title</a></b>
<span class="s">Details</span>
</td>
</table>
哪个returns:
Not found:<td id="topic1234"><a name="1234"></a>
<div>
<b><a href="/url">Title</a></b>
</div><span class="s">Details</span></td>
Found: <td id="topic2345"> <a name="2345"></a> <b><a href="/url">Title</a></b> <span class="s">Details</span> </td>
显然同样适用于第二个条件(即 span.s
)
请注意,在这种情况下,:root
选择器有效,因为 elem
的根元素是 td
而不是 table