如何获取元素的所有子文本节点(含间接子节点)?
问题:用Jsoup获取元素的所有嵌套子文本节点
我们需要获取某一元素的所有子文本节点,包括直接子文本节点和间接子文本节点(如孙节点、曾孙节点等)。但Jsoup的Element类提供的textNodes()方法仅返回直接子文本节点,无法满足需求。
示例HTML
<html> <head/> <body> <div class="erece mtmhp"> <a href="http://www.stackoverflow.com"> <span>Content 1</span> <span>Content 2</span> </a> </div> </body> </html>
我们的目标是从中分别获取Content 1和Content 2这两个文本节点。
初始示例代码(无法满足需求)
import java.io.File; import java.util.List; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.nodes.TextNode; import org.jsoup.select.Elements; public class TextNodeExpt { public static void main(String[] args) throws Exception { File fileObj = new File(args[0]); Document document = Jsoup.parse(fileObj, "UTF-8"); Elements divs = document.select("div.erece.mtmhp"); displaySubtendingTextNodes(divs); } protected static void displaySubtendingTextNodes(Elements divs) { for (Element div : divs) { Elements anchors = div.select("a"); for (Element anchor : anchors) { List<TextNode> textNodes = anchor.textNodes(); System.out.println(textNodes.size() + " text nodes found"); for(TextNode tn : textNodes) { System.out.println("[" + tn.getWholeText() + "]"); } } } } }
这段代码无法获取目标文本节点,因为anchor.textNodes()仅返回<a>标签的直接子文本节点,而<a>的直接子节点是<span>元素,没有直接文本节点。
解决方法:递归遍历所有子节点
通过递归遍历目标元素的所有子节点,筛选出非空白的文本节点,即可获取所有嵌套的子文本节点。完整实现如下:
import java.io.File; import java.util.ArrayList; import java.util.List; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; import org.jsoup.select.Elements; public class TextNodeExpt { public static void main(String[] args) throws Exception { File fileObj = new File(args[0]); Document document = Jsoup.parse(fileObj, "UTF-8"); Elements divs = document.select("div.erece.mtmhp"); displayAllSubtextNodes(divs); } protected static void displayAllSubtextNodes(Elements divs) { for (Element div : divs) { Elements anchors = div.select("a"); for (Element anchor : anchors) { List<TextNode> allTextNodes = new ArrayList<>(); textNodes(anchor, allTextNodes); System.out.println(allTextNodes.size() + " text nodes found"); for(TextNode tn : allTextNodes) { System.out.println("[" + tn.getWholeText() + "]"); } } } } protected static void textNodes(Node targetNode, List<TextNode> nodeList) { for (Node childNode : targetNode.childNodes()) { if (childNode instanceof TextNode && !((TextNode) childNode).isBlank()) { nodeList.add((TextNode)childNode); } else { textNodes(childNode, nodeList); } } } }
代码说明
textNodes方法递归遍历目标节点的所有子节点,判断如果是文本节点且非空白,就添加到传入的列表中- 调用时初始化一个空列表,传入方法后就能得到所有嵌套的文本节点
- 运行这段代码后,会正确输出
Content 1和Content 2
内容的提问来源于stack exchange,提问作者Sandeep
相关产品推荐
相关产品推荐

