You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java读取Excel类型XML文档时XPath查询失败的解决求助

Java读取Excel格式XML并导入数据库的解决方案

问题根源

你踩的坑主要是俩:一是XML带命名空间但你没处理,直接用无命名空间的XPath根本找不到节点;二是代码里getElementsByTagName("")传空参数,这肯定拿不到任何元素,而且你写的XPath路径/Worksheet/Data和实际XML的节点结构不匹配。

修正方案

1. 先搞定命名空间

Excel导出的XML(SpreadsheetML)都带默认命名空间urn:schemas-microsoft-com:office:spreadsheet,用DOM和XPath时必须先注册这个命名空间,不然解析器认不出节点。

2. 写对XPath路径

目标XML的实际数据节点层级是Workbook -> Worksheet -> Table -> Row -> Cell -> Data,得用带命名空间前缀的XPath才能定位。

3. 调整后的可运行代码

下面是改好的代码,能直接读取目标XML的数据,后续替换成JDBC代码就能存数据库:

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import java.io.*;
import java.net.URL;
import java.util.Iterator;

public class ExcelXmlReader {
    public static void main(String[] args) {
        try {
            // 从指定URL加载XML(也可替换成本地文件路径)
            URL xmlUrl = new URL("https://www.juntadeandalucia.es/datosabiertos/portal/dataset/91f3c95b-a2d2-4828-8880-99f8ea156d0e/resource/f7737217-65d6-4b00-bd10-2f82c69ae2f7/download/contratos-adjudicados-oct-23.xml");
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 必须开启命名空间支持,否则无法识别带命名空间的节点
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(xmlUrl.openStream());
            doc.getDocumentElement().normalize();

            XPath xPath = XPathFactory.newInstance().newXPath();
            // 注册命名空间前缀,用"ss"对应Excel的默认命名空间
            xPath.setNamespaceContext(new NamespaceContext() {
                @Override
                public String getNamespaceURI(String prefix) {
                    if ("ss".equals(prefix)) {
                        return "urn:schemas-microsoft-com:office:spreadsheet";
                    }
                    return null;
                }

                @Override
                public String getPrefix(String namespaceURI) {
                    return null;
                }

                @Override
                public Iterator getPrefixes(String namespaceURI) {
                    return null;
                }
            });

            // 正确的XPath:定位所有数据行
            String xpathExpr = "/ss:Workbook/ss:Worksheet/ss:Table/ss:Row";
            NodeList rowNodes = (NodeList) xPath.compile(xpathExpr).evaluate(doc, XPathConstants.NODESET);

            // 遍历每一行,读取单元格数据
            for (int i = 0; i < rowNodes.getLength(); i++) {
                Node rowNode = rowNodes.item(i);
                if (rowNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element rowElement = (Element) rowNode;
                    // 按命名空间获取单元格节点
                    NodeList cellNodes = rowElement.getElementsByTagNameNS("urn:schemas-microsoft-com:office:spreadsheet", "Cell");
                    StringBuilder rowData = new StringBuilder();
                    for (int j = 0; j < cellNodes.getLength(); j++) {
                        Element cellElement = (Element) cellNodes.item(j);
                        // 获取单元格内的Data节点文本内容
                        NodeList dataNodes = cellElement.getElementsByTagNameNS("urn:schemas-microsoft-com:office:spreadsheet", "Data");
                        if (dataNodes.getLength() > 0) {
                            rowData.append(dataNodes.item(0).getTextContent()).append("\t");
                        }
                    }
                    // 此处替换为JDBC代码即可将数据存入数据库
                    System.out.println(rowData.toString().trim());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

额外提醒

  • 存数据库别手写原生JDBC,用MyBatis或Spring JdbcTemplate,能省掉很多连接管理、异常处理的麻烦。
  • 如果XML文件很大,别用DOM解析,改用SAX解析,内存占用更低,SAX处理时同样要通过命名空间URI判断节点。
  • 先把XML下载到本地,用Notepad++或Chrome开发者工具查看节点结构,确认层级和命名空间后再写解析逻辑,比瞎试效率高。

内容的提问来源于stack exchange,提问作者FRENEK WHAT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 00:40:22