我正在尝试解析包含多个具有以下结构的单元格的HTML表格:
<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'属性,带有'href'属性的'a'元素和'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。
答案 0 :(得分:1)
:has(selector)
中的选择器包含父元素。我不认为>b
是JSoup中的有效选择器,但*>b
应该没问题且它允许任何父元素。所以这应该有效:
select("[id^=topic]"
+ ":has(* > b > a[href])"
+ ":has(* > span.s)")
编辑1回应评论:
为了使:has(selector)
的选择器更有可能是[id^=topic]
的直接孩子,您也可以这样做:
select("[id^=topic]"
+ ":has([id^=topic] > b > a[href])"
+ ":has([id^=topic] > span.s)")
这当然不是保证,因为父母的内在子女也可能带有以topic
开头的身份证。
<强> EDIT2 强>
与solution of user2340612类似,您可以通过将选择器分为两部分来确保。首先,我们匹配以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);
}
}
答案 1 :(得分:1)
我认为由于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>
返回:
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