Java读取复杂XML文件:无法读取BILLFIXED节点外的内容
问题分析
你的问题核心在于对XML节点层级的理解偏差:<BILLFINAL>、<BILLDUE>、<BILLOVERDUE>这些节点并非<BILLFIXED>的子节点,而是和<BILLFIXED>平级的直接子节点,都隶属于根节点<ENVELOPE>。你的原代码试图从<BILLFIXED>内部查找这些节点,自然无法获取到内容。
另外,你的XML结构是按「账单组」排列的:每一个<BILLFIXED>后面跟着对应的<BILLCL>、<BILLPDC>、<BILLFINAL>等节点,对应一条完整的账单条目。所以需要按顺序遍历<ENVELOPE>的所有子节点,把同属一个账单的节点关联起来处理。
解决方案
下面是修改后的代码,能正确读取每一组账单的完整数据:
首先,我们可以定义一个简单的Bill类来存储单条账单数据(用类管理数据会比直接打印更清晰):
class Bill { String billDate; String billRef; String billParty; String billCl; String billFinal; String billDue; String billOverdue; // 打印账单信息的方法 public void printBill() { System.out.println("账单日期: " + billDate); System.out.println("账单编号: " + billRef); System.out.println("往来方: " + billParty); System.out.println("账单金额: " + billCl); System.out.println("最终金额: " + billFinal); System.out.println("到期日: " + billDue); System.out.println("逾期天数: " + billOverdue); System.out.println("------------------------"); } }
然后是核心的XML读取逻辑:
try { File fXmlFile = new File("filepath"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(fXmlFile); doc.getDocumentElement().normalize(); // 获取根节点ENVELOPE的所有子节点 Element envelopeElement = doc.getDocumentElement(); NodeList childNodes = envelopeElement.getChildNodes(); Bill currentBill = null; for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); // 只处理元素节点(跳过XML中的换行、空格等文本节点) if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; String nodeName = element.getNodeName(); switch (nodeName) { case "BILLFIXED": // 遇到新的BILLFIXED,说明是新账单,先处理上一个未完成的账单 if (currentBill != null) { currentBill.printBill(); } currentBill = new Bill(); // 读取BILLFIXED内部的字段 currentBill.billDate = element.getElementsByTagName("BILLDATE").item(0).getTextContent(); currentBill.billRef = element.getElementsByTagName("BILLREF").item(0).getTextContent(); currentBill.billParty = element.getElementsByTagName("BILLPARTY").item(0).getTextContent(); break; case "BILLCL": if (currentBill != null) { currentBill.billCl = element.getTextContent(); } break; case "BILLFINAL": if (currentBill != null) { currentBill.billFinal = element.getTextContent(); } break; case "BILLDUE": if (currentBill != null) { currentBill.billDue = element.getTextContent(); } break; case "BILLOVERDUE": if (currentBill != null) { currentBill.billOverdue = element.getTextContent(); } break; // 处理空节点BILLPDC,可根据需求选择忽略或标记 case "BILLPDC": break; } } } // 遍历结束后,打印最后一条账单 if (currentBill != null) { currentBill.printBill(); } } catch (Exception e) { e.printStackTrace(); }
关键说明
- 遍历所有子节点:不再只查找
<BILLFIXED>,而是遍历<ENVELOPE>的所有直接子节点,确保不会遗漏平级的账单属性节点。 - 维护当前账单实例:每遇到一个
<BILLFIXED>就创建新的账单对象,后续的平级节点数据都填充到这个对象中,直到遇到下一个<BILLFIXED>或遍历结束。 - 过滤非元素节点:XML解析时会把换行、空格等文本节点也纳入结果,因此需要通过
node.getNodeType() == Node.ELEMENT_NODE筛选出实际的标签节点。
这样修改后,就能完整读取每一组账单的所有数据了。
内容的提问来源于stack exchange,提问作者Mostch Romi
相关产品推荐
相关产品推荐

