java怎么遍历document

使用 Document.getChildNodes() 获取子节点,递归遍历并判断节点类型为 ELEMENT_NODE

基础认知体系构建

1 文档模型分类

模型类型 核心特征 适用场景 Java标准库支持
DOM 树形结构/全量加载/随机访问 中小型文档/频繁查询修改 javax.xml.parsers
SAX 事件驱动/增量解析/低内存消耗 超大型文档/单次顺序处理 org.xml.sax
StAX 拉模式解析/游标控制/高效过滤 复杂数据抽取/流式处理 javax.xml.stream
Jsoup (HTML) 类jQuery API/宽松容错机制 HTML5文档/网页爬虫开发 org.jsoup

2 关键术语对照表

术语 说明 典型应用场景
Node 文档节点基类 所有元素/文本/注释的基础
Element 含子节点的元素节点 <book>, <title>等标签
Text 节点 段落文字/属性值
NamedNodeMap 属性集合 获取元素的id, class等
NodeList 有序节点集合 通过CSS选择器获取的结果集

DOM解析深度实践(以XML为例)

1 标准实现流程

// 1. 创建DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // 启用命名空间支持
// 2. 构建Document对象
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("books.xml"));
// 3. 遍历根节点下的所有子节点
NodeList bookList = doc.getElementsByTagName("book");
for (int i = 0; i < bookList.getLength(); i++) {
    Element book = (Element) bookList.item(i);
    // 4. 提取元素内容
    String title = book.getElementsByTagName("title").item(0).getTextContent();
    double price = Double.parseDouble(book.getElementsByTagName("price").item(0).getTextContent());
    // 5. 处理属性
    String category = book.getAttribute("category");
    // 6. 递归遍历子节点(可选)
    traverseChildren(book);
}
private void traverseChildren(Node parent) {
    NodeList children = parent.getChildNodes();
    for (int j = 0; j < children.getLength(); j++) {
        Node child = children.item(j);
        if (child.getNodeType() == Node.ELEMENT_NODE) {
            System.out.println("发现元素: " + child.getNodeName());
            traverseChildren(child); // 深度优先遍历
        } else if (child.getNodeType() == Node.TEXT_NODE) {
            System.out.println("文本内容: " + child.getTextContent().trim());
        }
    }
}

2 高级技巧组合

技术手段 实现方式 优势体现
XPath表达式 XPathFactory.newInstance().newXPath().evaluate() 精准定位复杂路径节点
迭代器模式 NodeIterator配合while(iterator.hasNext())循环 避免显式索引管理
Lambda表达式(Java8+) Arrays.stream(nodeList).forEach(node -> ...) 简化集合操作
并行流处理 Arrays.stream(nodeList).parallel().forEach(...) 提升多核CPU利用率

3 性能优化策略

优化方向 具体措施 效果评估
缓存机制 对重复访问的节点进行软引用缓存 减少DOM树遍历次数
批量处理 将多次getElementsByTagName合并为单次查询 降低I/O操作频率
懒加载 仅在需要时展开子节点 初始加载时间缩短70%+
内存监控 使用Runtime.getRuntime().totalMemory()跟踪内存变化 防止OOM异常发生

HTML文档特殊处理(Jsoup方案)

1 典型用法示例

// 1. 解析HTML文档
Document doc = Jsoup.connect("https://example.com").get();
// 2. 选择器方式遍历
Elements links = doc.select("a[href]"); // 获取所有带href属性的链接
for (Element link : links) {
    String url = link.attr("href");
    String text = link.text();
    // ...后续处理逻辑
}
// 3. 修改文档结构
Element table = doc.selectFirst("table");
table.select("tr:odd").addClass("highlight"); // 隔行变色效果
System.out.println(doc.html()); // 输出修改后的HTML

2 HTML特有处理要点

问题类型 解决方案 注意事项
自闭合标签 Jsoup自动规范化处理<img />为<img> 无需手动补全
特殊字符转义 StringEscapeUtils.unescapeHtml4()处理实体编码 防止XSS攻击需二次过滤
CSS样式提取 element.attr("style")可直接获取内联样式 外部样式表需单独解析

SAX与StAX流式解析对比

1 SAX事件驱动模型

public class SaxParser extends DefaultHandler {
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attrs) {
        if ("book".equals(qName)) {
            currentBook = new Book();
            // 初始化新书籍对象
        }
    }
    @Override
    public void characters(char[] ch, int start, int length) {
        if (currentBook != null) {
            currentBook.setContent(new String(ch, start, length));
        }
    }
    @Override
    public void endElement(String uri, String localName, String qName) {
        if ("book".equals(qName)) {
            books.add(currentBook);
            currentBook = null;
        }
    }
}

优势:内存占用仅为DOM的1/5~1/10,适合GB级大文件处理;劣势:无法随机访问节点,需自行维护状态机。

java怎么遍历document

2 StAX拉模式解析

XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("large.xml"));
while (reader.hasNext()) {
    int event = reader.next();
    switch (event) {
        case XMLStreamReader.START_ELEMENT:
            if ("important".equals(reader.getLocalName())) {
                // 处理关键元素
            }
            break;
        case XMLStreamReader.CHARACTERS:
            // 处理文本内容
            break;
        // ...其他事件处理
    }
}

特点:结合推/拉模式优势,可通过peek()预读下一个事件,适合复杂条件判断场景。


常见问题解决方案库

Q1: 如何处理XML命名空间冲突?

A: 在创建DocumentBuilder时设置命名空间感知:

java怎么遍历document

factory.setNamespaceAware(true);
// 然后通过带URI的完整名称访问元素:
NodeList nodes = doc.getElementsByTagNameNS("http://example.com/ns", "localName");

补充说明:若遇到未知命名空间,可通过builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)禁用外部DTD加载。

Q2: 遍历时出现”NullPointerException”如何解决?

A: 常见原因及对策:
| 错误位置 | 根本原因 | 解决方案 |
|————————|——————————|———————————–|
| item(i)返回null | 索引越界或标签不存在 | 添加if (i < nodeList.getLength())校验 |
| getTextContent()为空 | 节点类型不匹配(如注释节点) | 先检查getNodeType()是否为ELEMENT_NODE |
| 属性获取失败 | 属性未定义 | 使用hasAttribute()前置判断 |
| Jsoup选择器无结果 | CSS语法错误或DOM未完全加载 | 添加await().atMost(5, SECONDS)等待异步加载 |

java怎么遍历document


选型决策矩阵

评价维度 DOM SAX StAX Jsoup (HTML)
内存效率 ★☆☆☆☆(差) ★★★★★(优) ★★★★☆(良) ★★★☆☆(中)
开发便捷性 ★★★★☆(易) ★★☆☆☆(难) ★★★☆☆(中) ★★★★★(极优)
随机访问能力 ★★★★★(强) ★☆☆☆☆(弱) ★★★☆☆(中) ★★★☆☆(中)
大数据适配性 ★☆☆☆☆(差) ★★★★★(优) ★★★★☆(良) ★★☆☆☆(差)
HTML兼容性 ★☆☆☆☆(差) ★☆☆☆☆(差) ★☆☆☆☆(差) ★★★★★(极优)
修改文档能力 ★★★★★(强) ★☆☆☆☆(弱) ★★☆☆☆(中)

原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/100791.html

赞 (0)
酷盾叔的头像酷盾叔
上一篇 2025年8月10日 19:04
下一篇 2025年8月10日 19:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-880-8834

在线咨询: QQ交谈

邮件:HI@E.KD.CN