
本教程详细讲解如何使用java dom解析器高效处理多层xml文件。文章首先指出 `getelementsbytagname` 的全局搜索特性可能导致的问题,并提供了在特定父节点下进行局部查找的解决方案。接着,教程引入了面向对象的数据建模方法,通过创建pojo类来存储和关联解析出的数据,最终实现对多层xml数据的结构化、分组式输出,确保数据逻辑清晰且易于管理。
在现代软件开发中,XML文件作为一种通用的数据交换格式被广泛应用。当XML文件结构复杂,包含多层嵌套和关联数据时,如何有效地解析并提取所需信息成为一项重要任务。本教程将以一个员工信息XML文件为例,详细介绍如何利用Java DOM(Document Object Model)解析器处理这类多层结构,并实现数据的有效组织和输出。
理解多层XML结构
我们以以下XML文件为例,该文件包含员工列表(employee_list)、职位详情(position_details)和员工附加信息(employee_info)三个主要类别:
Andrei Rus 23 Ion Popescu 25 Georgiana Domide 33 Junior Developer Java 1 Developer Python 3 Senior Developer C 5 AndreiR Timisoara 1999 0 IonP Timisoara 1997 0 GeorgianaD Arad 1989 0
该XML文件的根元素是,其下包含三个子元素:、和。每个子元素内部又包含多条具体记录,并通过 ID 和 ref 属性进行关联。
Java DOM解析器基础
Java DOM解析器通过将整个XML文档加载到内存中,构建一个树形结构(DOM树),从而允许开发者通过导航树来访问和操作XML数据。主要涉及的类包括:
立即学习“Java免费学习笔记(深入)”;
DocumentBuilderFactory: 用于创建 DocumentBuilder 实例。DocumentBuilder: 用于解析XML文件并生成 Document 对象。Document: 代表整个XML文档,是DOM树的根。Node: DOM树中的基本单元,可以是元素、属性、文本等。Element: Node 的一个子类型,代表XML元素。NodeList: 包含一组 Node 对象的列表。
getElementsByTagName 的全局搜索问题
在使用 Document.getElementsByTagName(String name) 方法时,需要特别注意其全局搜索的特性。该方法会在整个XML文档中查找所有匹配指定标签名的元素,而不仅仅是当前节点的直接子元素。
例如,在上述XML文件中,如果直接调用 doc.getElementsByTagName(“employee”),它不仅会找到 下的三个 元素,还会找到根元素 本身,导致返回的 NodeList 长度比预期多1。当尝试从根 元素中获取 等子元素时,由于这些子元素并非其直接子节点,程序可能会出现 NullPointerException 或返回不正确的数据。
LimeSurvey在线问卷管理系统
LimeSurvey是一款在线问卷管理系统,具有问卷的设计、修改、发布、回收和统计等多项功能。同时它也是一个开源软件,其最新版本的软件包可以完全免费获取和使用。它集成了调查程序开发、调查问卷的发布以及数据收集等功能,使用它,用户不必了解这些功能的编程细节。 网上收集的调查数据可以导出多种文件格式以便分析,例如 spss数据格式 *.dat文件。
198 查看详情
局部化元素查找
为了避免全局搜索带来的问题,并确保只在特定父节点下查找子元素,我们应该先获取父节点,然后在其上下文中使用 getElementsByTagName。
以下是针对 employee_list、position_details 和 employee_info 三个类别的正确解析方法:
import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.io.File;import java.util.ArrayList;import java.util.List;public class XmlParser { public static void main(String[] args) { try { File xmlFile = new File("employees.xml"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(xmlFile); doc.getDocumentElement().normalize(); // 规范化文档,合并相邻的文本节点 System.out.println("Root element: " + doc.getDocumentElement().getNodeName()); System.out.println("-----------------------------------------------------------------------------"); // 解析 employee_list 类别 System.out.println("Parsing Employee List:"); NodeList employeeListNodes = doc.getElementsByTagName("employee_list"); if (employeeListNodes.getLength() > 0) { Element employeeListElement = (Element) employeeListNodes.item(0); NodeList employees = employeeListElement.getElementsByTagName("employee"); System.out.println("Total Employees found: " + employees.getLength()); for (int i = 0; i 0) { Element positionDetailsElement = (Element) positionDetailsNodes.item(0); NodeList positions = positionDetailsElement.getElementsByTagName("position"); System.out.println("Total Positions found: " + positions.getLength()); for (int i = 0; i 0) { Element employeeInfoElement = (Element) employeeInfoNodes.item(0); NodeList details = employeeInfoElement.getElementsByTagName("detail"); System.out.println("Total Details found: " + details.getLength()); for (int i = 0; i 0) { Node node = nodeList.item(0); if (node != null && node.getNodeType() == Node.ELEMENT_NODE) { return node.getTextContent(); } } return ""; } // 辅助方法:获取子元素的属性值 private static String getAttributeValue(String tagName, String attrName, Element element) { NodeList nodeList = element.getElementsByTagName(tagName); if (nodeList != null && nodeList.getLength() > 0) { Node node = nodeList.item(0); if (node != null && node.getNodeType() == Node.ELEMENT_NODE) { Element subElement = (Element) node; return subElement.getAttribute(attrName); } } return ""; }}
在上述代码中,我们首先通过 doc.getElementsByTagName(“employee_list”) 获取到 元素,然后在其上调用 getElementsByTagName(“employee”) 来获取所有员工记录。这种分步查找的方式确保了我们只在预期的上下文中进行搜索。
结构化数据存储与分组输出
直接打印解析出的数据虽然简单,但对于多层关联数据,更专业的做法是将其映射到Java对象(POJO,Plain Old Java Object)中,以便于后续的数据处理和统一输出。我们可以为 Employee、PositionDetail 和 EmployeeInfo 定义相应的POJO类。
1. 定义POJO类
// Employee.javapublic class Employee { private String id; private String firstname; private String lastname; private int age; private String positionSkillRef; private String detailRef; // Constructor public Employee(String id, String firstname, String lastname, int age, String positionSkillRef, String detailRef) { this.id = id; this.firstname = firstname; this.lastname = lastname; this.age = age; this.positionSkillRef = positionSkillRef; this.detailRef = detailRef; } // Getters public String getId() { return id; } public String getFirstname() { return firstname; } public String getLastname() { return lastname; } public int getAge() { return age; } public String getPositionSkillRef() { return positionSkillRef; } public String getDetailRef() { return detailRef; } // Setters (optional, if data is immutable after parsing) public void setId(String id) { this.id = id; } public void setFirstname(String firstname) { this.firstname = firstname; } public void setLastname(String lastname) { this.lastname = lastname; } public void setAge(int age) { this.age = age; } public void setPositionSkillRef(String positionSkillRef) { this.positionSkillRef = positionSkillRef; } public void setDetailRef(String detailRef) { this.detailRef = detailRef; } @Override public String toString() { return "Employee{" + "id='" + id + '\'' + ", firstname='" + firstname + '\'' + ", lastname='" + lastname + '\'' + ", age=" + age + ", positionSkillRef='" + positionSkillRef + '\'' + ", detailRef='" + detailRef + '\'' + '}'; }}// PositionDetail.javapublic class PositionDetail { private String id; private String role; private String skillName; private int experience; // Constructor public PositionDetail(String id, String role, String skillName, int experience) { this.id = id; this.role = role; this.skillName = skillName; this.experience = experience; } // Getters public String getId() { return id; } public String getRole() { return role; } public String getSkillName() { return skillName; } public int getExperience() { return experience; } // Setters public void setId(String id) { this.id = id; } public void setRole(String role) { this.role = role; } public void setSkillName(String skillName) { this.skillName = skillName; } public void setExperience(int experience) { this.experience = experience; } @Override public String toString() { return "PositionDetail{" + "id='" + id + '\'' + ", role='" + role + '\'' + ", skillName='" + skillName + '\'' + ", experience=" + experience + '}'; }}// EmployeeInfo.javapublic class EmployeeInfo { private String id; private String username; private String residence; private int yearOfBirth; private String phone; // Constructor public EmployeeInfo(String id, String username, String residence, int yearOfBirth, String phone) { this.id = id; this.username = username; this.residence = residence; this.yearOfBirth = yearOfBirth; this.phone = phone; } // Getters public String getId() { return id; } public String getUsername() { return username; } public String getResidence() { return residence; } public int getYearOfBirth() { return yearOfBirth; } public String getPhone() { return phone; } // Setters public void setId(String id) { this.id = id; } public void setUsername(String username) { this.username = username; } public void setResidence(String residence) { this.residence = residence; } public void setYearOfBirth(int yearOfBirth) { this.yearOfBirth = yearOfBirth; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "EmployeeInfo{" + "id='" + id + '\'' + ", username='" + username + '\'' + ", residence='" + residence + '\'' + ", yearOfBirth=" + yearOfBirth + ", phone='" + phone + '\'' + '}'; }}
2. 解析数据并填充POJO列表
接下来,修改解析逻辑,将数据填充到 List 集合中。为了方便通过 ref 属性查找关联数据,我们可以使用 Map 来存储 PositionDetail 和 EmployeeInfo,其中键为它们的 ID。
import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.io.File;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class AdvancedXmlParser { public static void main(String[] args) { List employees = new ArrayList(); Map positionDetailsMap = new HashMap(); Map employeeInfoMap = new HashMap(); try { File xmlFile = new File("employees.xml"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(xmlFile); doc.getDocumentElement().normalize(); // 1. 解析 employee_list 并填充 employees 列表 NodeList employeeListNodes = doc.getElementsByTagName("employee_list"); if (employeeListNodes.getLength() > 0) { Element employeeListElement = (Element) employeeListNodes.item(0); NodeList employeeNodes = employeeListElement.getElementsByTagName("employee"); for (int i = 0; i 0) { Element positionDetailsElement = (Element) positionDetailsNodes.item(0); NodeList positionNodes = positionDetailsElement.getElementsByTagName("position"); for (int i = 0; i 0) { Element employeeInfoElement = (Element) employeeInfoNodes.item(0); NodeList detailNodes = employeeInfoElement.getElementsByTagName("detail"); for (int i = 0; i < detailNodes.getLength(); i++) { Node detailNode = detailNodes.item(i); if (detailNode.getNodeType() == Node.ELEMENT_NODE) { Element detailElement =
以上就是使用Java DOM解析多层XML文件的教程的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/961360.html
微信扫一扫
支付宝扫一扫