Apache XML Commons External 介绍与选型指南
梳理 Apache XML Commons External(xml-apis)标准 XML 接口 jar 的定位、版本历史与 jar 内容实测结论,辨析其与 JDK 内置接口、Xerces-J 的配套关系并给出选型建议。
Apache XML Commons External 介绍与选型指南
目标:讲清 Apache XML Commons External(对外坐标
xml-apis:xml-apis)这个"标准 XML 接口 jar"的定位、版本历史与 jar 内容构成,实测辨析它与 JDK 内置 XML 接口、Apache Xerces-J 的配套关系,给出"现代项目还需不需要引入"的选型结论。全部命令与回显已在 Ubuntu 22.04 + OpenJDK 17(另装 OpenJDK 8 做历史对照)+ Maven 3.9.9 实测通过。
一、环境信息
本章列出实测环境与版本核验命令,后续所有命令与回显均来自该环境。
- 操作系统:Ubuntu 22.04.5 LTS(x86_64),主测 JDK:OpenJDK 17.0.20.1,对照 JDK:OpenJDK 1.8.0_504
- 构建工具:Apache Maven 3.9.9(解压于
/root/apache-maven-3.9.9) - 实测对象:xml-apis 1.4.01、xml-apis 2.0.2、xml-apis-ext 1.3.04、xercesImpl 2.12.2
- 实验目录:
/root/xmltest(jar 下载盘点)、/root/factorydemo(工厂加载演示)、/root/endorsed(JDK8 endorsed 实验)
版本核验(实测回显):
java -version # 主测 JDK
/usr/lib/jvm/java-8-openjdk-amd64/bin/java -version # 对照 JDK
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
openjdk version "1.8.0_504"
OpenJDK Runtime Environment (build 1.8.0_504-8u504-ga-1ubuntu1~22.04.3-b01)
OpenJDK 64-Bit Server VM (build 25.504-b01, mixed mode)
二、软件概述
2.1 项目定位
Apache XML Commons 是 xml.apache.org 下的基础子项目,自身不实现任何 XML 解析,职责是把 W3C DOM、SAX、JAXP、StAX 这些由 W3C、SAX 项目(David Megginson)、Sun/BEA 制定的标准接口编译成一份 Apache 托管的接口 jar,供 Xerces-J、Xalan-J 引用同一份契约,并向 Apache 体系之外(Batik、Fop、老版 Axis 等第三方项目)发布——这就是 "External" 的含义。对外坐标为 xml-apis:xml-apis(主接口包)与 xml-apis:xml-apis-ext(DOM 扩展包)。
💡 技术拓展:一套 XML 标准接口存在多种处理 API,各有分工——
API 处理模型 特点 典型场景 SAX 流式、事件回调 顺序读取、内存占用极低、不可回溯 大文件顺序解析 DOM 树模型、整棵加载 可随机访问、可写回、内存开销大 需改写或随机遍历文档 StAX 流式、拉取式 调用方主动 next() 拉事件,比 SAX 直观 中等规模流式处理 JAXP 工厂门面 统一入口发现解析器实现,屏蔽底层实现 几乎所有 Java XML 程序 xml-apis 1.4.01 把四类接口打进同一个 jar(三章实测),本文以 JAXP 工厂机制为主线展开。
2.2 Maven Central 版本全表(实测)
确认坐标 xml-apis:xml-apis 到底有哪些版本(输出节选,实测首尾):
curl -sS https://repo1.maven.org/maven2/xml-apis/xml-apis/maven-metadata.xml
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<versioning>
<latest>2.0.2</latest>
<release>2.0.2</release>
<versions>
<version>1.0.b2</version>
<version>1.2.01</version>
<version>1.3.02</version>
<version>1.3.03</version>
<version>1.3.04</version>
<version>1.4.01</version>
<version>2.0.0</version>
<version>2.0.2</version>
</versions>
<lastUpdated>20120626170101</lastUpdated>
</versioning>
</metadata>
两个事实值得注意:最新与 release 版本是 2.0.2 而非流传较广的 1.4.01;元数据 lastUpdated 为 2012-06-26,此后项目在 Central 上再未更新。坊间常提的 "1.4.02" 并不存在,实测请求该版本直接 404:
curl -s -o /dev/null -w "1.4.02 http_code=%{http_code}\n" https://repo1.maven.org/maven2/xml-apis/xml-apis/1.4.02/xml-apis-1.4.02.jar
curl -s -o /dev/null -w "1.4.01 http_code=%{http_code}\n" https://repo1.maven.org/maven2/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar
1.4.02 http_code=404
1.4.01 http_code=200
用 jar 文件的 Last-Modified 响应头还原发布时间线:
curl -sI https://repo1.maven.org/maven2/xml-apis/xml-apis/2.0.2/xml-apis-2.0.2.jar | grep -i '^last-modified'
curl -sI https://repo1.maven.org/maven2/xml-apis/xml-apis/1.3.04/xml-apis-1.3.04.jar | grep -i '^last-modified'
curl -sI https://repo1.maven.org/maven2/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar | grep -i '^last-modified'
last-modified: Tue, 22 Nov 2005 18:28:38 GMT
last-modified: Fri, 22 Dec 2006 13:37:52 GMT
last-modified: Sat, 20 Aug 2011 00:11:11 GMT
即 2.0.0/2.0.2 于 2005-11-22 上传(面向 JAXP 1.4 时代、与 JDK 5+ 内置接口对齐的精简版)、1.3.04 于 2006-12-22(DOM 2 / JAXP 1.3 时代的主流版本,仍被大量老依赖传递引用)、1.4.01 于 2011-08-20(接口最全、生态引用最广)。版本号大小与发布时间并不单调,选型应以 jar 内容与目标 JDK 为准而非数字大小。
三、核心架构
3.1 jar 包内容盘点(实测)
下载四个实测对象并核对指纹(xercesImpl 为配套实现,一并取回用于对比):
mkdir -p /root/xmltest && cd /root/xmltest
B=https://repo1.maven.org/maven2
curl -sSLo xml-apis-1.4.01.jar $B/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar
curl -sSLo xml-apis-2.0.2.jar $B/xml-apis/xml-apis/2.0.2/xml-apis-2.0.2.jar
curl -sSLo xml-apis-ext-1.3.04.jar $B/xml-apis/xml-apis-ext/1.3.04/xml-apis-ext-1.3.04.jar
curl -sSLo xercesImpl-2.12.2.jar $B/xerces/xercesImpl/2.12.2/xercesImpl-2.12.2.jar
sha256sum xml-apis-1.4.01.jar xml-apis-2.0.2.jar
a840968176645684bb01aed376e067ab39614885f9eee44abe35a5f20ebe7fad xml-apis-1.4.01.jar
8232f3482c346d843e5e3fb361055771c1acc105b6d8a189eb9018c55948cf9f xml-apis-2.0.2.jar
四个 jar 实测大小:xml-apis-1.4.01 为 216K(346 个类)、xml-apis-2.0.2 为 107K(184 个类)、xml-apis-ext-1.3.04 为 84K(192 个类)、xercesImpl-2.12.2 为 1413K(962 个类)。用 jar tf 统计 1.4.01 的三级包结构:
jar tf xml-apis-1.4.01.jar | grep -c '\.class$'
jar tf xml-apis-1.4.01.jar | grep '\.class$' | awk -F/ '{print $1"/"$2"/"$3}' | sort | uniq -c | sort -rn
346
150 org/w3c/dom
44 org/xml/sax
41 javax/xml/stream
33 javax/xml/transform
24 javax/xml/xpath
19 javax/xml/validation
15 javax/xml/parsers
15 javax/xml/datatype
3 javax/xml/namespace
1 org/apache/xmlcommons
1 javax/xml/XMLConstants
同口径看 xml-apis-ext 1.3.04 的构成(与主包完全不重叠):
jar tf xml-apis-ext-1.3.04.jar | grep '\.class$' | awk -F/ '{print $1"/"$2"/"$3"/"$4}' | sort | uniq -c | sort -rn
161 org/w3c/dom/svg
29 org/w3c/css/sac
2 org/w3c/dom/smil
盘点结论:1.4.01 覆盖 org.w3c.dom、org.xml.sax 与 javax.xml 全家(transform/xpath/validation/parsers/datatype/namespace/stream),外加唯一的实现工具类 org.apache.xmlcommons.Version;xml-apis-ext 则是另一组内容——SVG DOM 接口(161 类)、SAC(CSS 解析接口,29 类)与 SMIL(2 类),供 Batik 等图形项目使用。
3.2 内置 Xerces 默认实现的设计(实测)
一个容易被忽略的细节:xml-apis 1.4.01 的工厂类内部把 Apache Xerces 的 JAXP 实现类硬编码为默认 fallback;MANIFEST 中也按包声明了承载的规格(SAX 2.0.2 (sax2r3)、DOM Level 3 Core/Load and Save、JAXP 1.4、StAX 1.0),可通过 unzip -p xml-apis-1.4.01.jar META-INF/MANIFEST.MF 复核。必须反编译 jar 内的类文件本身——用 javap 指定类名时 JVM 会优先解析到 JDK 内置同名类,得到 JDK 版本字节码,结论会失真;对解压出的类文件直接反编译:
mkdir -p /tmp/xjar && cd /tmp/xjar && unzip -oq /root/xmltest/xml-apis-1.4.01.jar 'javax/*'
javap -c -p /tmp/xjar/javax/xml/parsers/DocumentBuilderFactory.class | sed -n '/newInstance()/,/areturn/p' | head -6
javap -c -p /tmp/xjar/javax/xml/datatype/DatatypeFactory.class | grep '// String org' | head -1
public static javax.xml.parsers.DocumentBuilderFactory newInstance();
Code:
0: ldc #8 // String javax.xml.parsers.DocumentBuilderFactory
2: ldc #9 // String org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
4: invokestatic #10 // Method javax/xml/parsers/FactoryFinder.find:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
7: checkcast #11 // class javax/xml/parsers/DocumentBuilderFactory
10: areturn
4: ldc #58 // String org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl
结论:xml-apis 1.4.01 把 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl(Xerces-J 的 JAXP 适配层)写死为默认实现类名(SAXParserFactory 同理为 org.apache.xerces.jaxp.SAXParserFactoryImpl)。它从设计上就是与 Xerces-J 成对交付:接口在 xml-apis、实现在 xercesImpl,缺一即抛错(JDK8 实测证据见 5.1)。
四、功能特性
4.1 接口覆盖面(实测汇总)
基于三章 jar tf 实测与 MANIFEST 规格声明,1.4.01 的覆盖面汇总:
| 包 | 规格 | 类数(实测) | 作用 |
|---|---|---|---|
| org.w3c.dom(含 events/ls/ranges/traversal/views/bootstrap 子包) | DOM Level 3 | 150 | DOM 树模型接口 |
| org.xml.sax(含 ext/helpers 子包) | SAX 2.0.2 (sax2r3) | 44 | 流式解析接口 |
| javax.xml.stream | StAX 1.0 | 41 | 拉取式流处理接口 |
| javax.xml.transform / xpath / validation / parsers / datatype / namespace / XMLConstants | JAXP 1.4 | 111 | 转换/XPath/校验/解析等 JAXP 门面 |
| org.apache.xmlcommons.Version | 无 | 1 | 版本打印工具类 |
解读:xml-apis 是"四合一"接口包,比 2.0.2(184 类,仅 DOM/SAX/transform/parsers)覆盖广得多,这是 1.4.01 成为生态引用最广版本的原因;jar 里唯一的"活代码"可独立运行验证:
java -cp xml-apis-1.4.01.jar org.apache.xmlcommons.Version
XmlCommonsExternal 1.4.01
4.2 只有接口、没有实现、没有服务注册(实测)
xml-apis 不含任何解析器实现类,也不带 JAXP 服务注册文件,实测验证:
jar tf xml-apis-1.4.01.jar | grep -c 'META-INF/services' ; echo "exit=$?"
jar tf xercesImpl-2.12.2.jar | grep 'META-INF/services'
0
exit=1
META-INF/services/javax.xml.datatype.DatatypeFactory
META-INF/services/javax.xml.parsers.DocumentBuilderFactory
META-INF/services/javax.xml.parsers.SAXParserFactory
META-INF/services/javax.xml.stream.XMLEventFactory
META-INF/services/javax.xml.validation.SchemaFactory
META-INF/services/org.w3c.dom.DOMImplementationSourceList
META-INF/services/org.xml.sax.driver
对比结论:xml-apis 的 META-INF 下只有 MANIFEST.MF 一个文件(services 计数 0,grep 无命中退出码 1);配套实现 xercesImpl 2.12.2 自带 7 个 services 注册文件,JAXP 工厂正是靠这些文件找到 Xerces 实现——只引 xml-apis 不引实现 jar 时,工厂回落到 JDK 内置实现(五章实测)。
五、适用场景与限制
5.1 JDK 8 时代:endorsed 覆盖机制(历史用法实测)
JDK 8 上 org.w3c.dom、org.xml.sax、javax.xml.parsers 等接口已内置在 rt.jar,xml-apis 当年的典型用法是放进 endorsed 目录覆盖 rt.jar 的旧接口。默认状态(未放 endorsed)用 -verbose:class 观察关键类加载来源(演示程序 FactoryDemo8 见《Apache XML Commons External 在 Ubuntu 22.04 集成使用指南》五章,同一程序可直接编译复现):
/usr/lib/jvm/java-8-openjdk-amd64/bin/java -verbose:class -cp /root/factorydemo/. FactoryDemo8 2>&1 | grep '\[Loaded \(javax\.xml\.parsers\.DocumentBuilderFactory \|org\.w3c\.dom\.Node \|com\.sun\.org\.apache\.xerces\.internal\.jaxp\.DocumentBuilderFactoryImpl \)'
[Loaded javax.xml.parsers.DocumentBuilderFactory from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar]
[Loaded com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar]
[Loaded org.w3c.dom.Node from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar]
把 xml-apis 与 xercesImpl 同时放入 /root/endorsed 后再看:
/usr/lib/jvm/java-8-openjdk-amd64/bin/java -verbose:class -Djava.endorsed.dirs=/root/endorsed -cp /root/factorydemo/. FactoryDemo8 2>&1 | grep '\[Loaded \(javax\.xml\.parsers\.DocumentBuilderFactory \|org\.w3c\.dom\.Node \|org\.apache\.xerces\.jaxp\.DocumentBuilderFactoryImpl \)'
[Loaded javax.xml.parsers.DocumentBuilderFactory from /root/endorsed/xml-apis-1.4.01.jar]
[Loaded org.apache.xerces.jaxp.DocumentBuilderFactoryImpl from /root/endorsed/xercesImpl-2.12.2.jar]
[Loaded org.w3c.dom.Node from /root/endorsed/xml-apis-1.4.01.jar]
实测解读:endorsed 生效时接口类(DocumentBuilderFactory、Node)确实从 endorsed 目录的 xml-apis 加载、实现类从 endorsed 的 xercesImpl 加载——这就是"xml-apis + endorsed + Xerces"经典组合的底层原理。另一关键实测:endorsed 只放 xml-apis、不放 xercesImpl 会直接报错:
mkdir -p /root/endorsed_only && cp xml-apis-1.4.01.jar /root/endorsed_only/
/usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djaxp.debug=1 -Djava.endorsed.dirs=/root/endorsed_only -cp /root/factorydemo/. FactoryDemo8 2>&1 | head -4
JAXP: find factoryId =javax.xml.parsers.DocumentBuilderFactory
JAXP: loaded from fallback value: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
Exception in thread "main" javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.DocumentBuilderFactoryImpl not found
at javax.xml.parsers.DocumentBuilderFactory.newInstance(Unknown Source)
报错根因正是 3.2 反编译所见:xml-apis 工厂类把 Xerces 实现写死为默认 fallback,endorse 了接口却没有配套实现,查找即失败。
💡 技术拓展:JDK 8 的 JAXP 工厂发现顺序为「系统属性 → jaxp.properties → classpath 的 META-INF/services → 默认实现」,endorsed 则在类加载层用外部 jar 顶替 rt.jar 接口类。JDK 9 模块化后 endorsed 整体移除,替代思路是「升级模块」(--upgrade-module-path)与 classpath services 注册;老的 endorsed 用法在 JDK 9+ 直接拒绝启动(5.2 实测)。
5.2 JDK 9+(实测 JDK 17):接口被 java.xml 模块遮蔽、endorsed 已移除
JDK 17 上结论完全不同:内置 java.xml 模块导出了 org.w3c.dom(含 events/ls/ranges/traversal/views/bootstrap)、org.xml.sax(含 ext)、javax.xml 全家等全部同名包(java --describe-module java.xml 可复核),classpath 上的 xml-apis 被完全遮蔽。用工厂演示程序对比两种 classpath(程序源码见集成指南第五章):
cd /root/factorydemo
java -cp . FactoryDemo
java -cp /root/xmltest/xml-apis-1.4.01.jar:. FactoryDemo
DocumentBuilderFactory impl -> com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
SAXParserFactory impl -> com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
API org.w3c.dom.Node module -> java.xml
API org.xml.sax.XMLReader module -> java.xml
DocumentBuilderFactory impl -> com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
SAXParserFactory impl -> com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
API org.w3c.dom.Node module -> java.xml
API org.xml.sax.XMLReader module -> java.xml
两种 classpath 输出完全一致:无论 xml-apis 是否在 classpath,Node、XMLReader 的加载模块始终是 java.xml——JDK 17 上 xml-apis 里的同名接口类是"死代码",永远不会被加载。再实测 endorsed 移除结论:
java -Djava.endorsed.dirs=/root/endorsed -cp . FactoryDemo
echo "exit=$?"
-Djava.endorsed.dirs=/root/endorsed is not supported. Endorsed standards and standalone APIs
in modular form will be supported via the concept of upgradeable modules.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
exit=1
JVM 直接拒绝启动(退出码 1)。"JDK 17 下 endorsed 已移除"为实测确认事实而非文档推测。
5.3 适用结论
- 仍需要它的场景只剩两类:只能跑在 JDK 8 上、通过 endorsed 与 Xerces-J 严格配对的遗留工程;以及个别老库(老版 Batik/Fop 等)把 xml-apis-ext 的 SVG DOM/SAC 接口声明为编译期依赖。
- 不需要它的场景:JDK 9 及以上的一切新工程——接口全部内置在 java.xml 模块且优先加载,引入 xml-apis 无任何效果,还背上 216KB 冗余与停更依赖的审计负担。
- 硬性限制:只有接口没有实现(4.2 实测),单独引入无法完成解析;项目 2012 年后停更,不会有面向新 JDK 的适配更新。
六、同类选型对比
把"XML 标准接口从哪来"的四个选项放在一张表里(版本均为本次实测版本):
| 方案 | 性质 | 是否需引入 | 实测大小 | 适用判断 |
|---|---|---|---|---|
| JDK 内置 java.xml 模块 | 接口 + 内置实现(Xerces 内嵌版) | 无需,开箱即用 | 随 JDK | JDK 9+ 项目默认且推荐来源 |
| xml-apis:xml-apis 1.4.01 | 纯接口 jar(DOM/SAX/JAXP/StAX 四合一) | 需引入 | 216KB / 346 类 | 仅 JDK 8 遗留工程、与 Xerces-J 配对时 |
| xml-apis:xml-apis 2.0.2 | 精简接口 jar | 需引入 | 107KB / 184 类 | 老依赖声明该版本时沿用,无主动选择价值 |
| xml-apis:xml-apis-ext 1.3.04 | SVG DOM + SAC + SMIL 接口 | 需引入 | 84KB / 192 类 | Batik 等图形类老项目的传递依赖 |
| xerces:xercesImpl 2.12.2 | 解析器实现(含 JAXP services 注册) | 按需引入 | 1413KB / 962 类 | 需指定 Xerces 版本/行为时引入,自动接管工厂 |
选型建议一句话:现代 JDK 项目接口一律用 JDK 内置,实现按需用 xercesImpl 的 services 机制切换;xml-apis 只会出现在存量依赖里,能排除就排除。另需区分两个名字相近的项目:本篇的 XML Commons External 是接口 jar(坐标 xml-apis),XML Commons 的另一组件 Resolver 是 Catalog 解析实体(坐标 xml-commons:xml-commons-resolver),参见《Apache XML Commons Resolver》专栏文档;集成实操全部展开在《Apache XML Commons External 在 Ubuntu 22.04 集成使用指南》。
七、参考链接
- Apache XML Commons 项目主页:https://xerces.apache.org/xml-commons/
- Maven Central 坐标页(xml-apis / xml-apis-ext):https://repo1.maven.org/maven2/xml-apis/xml-apis/
- Xerces-J 项目主页:https://xerces.apache.org/xerces2-j/
- SAX 规格站点:http://www.saxproject.org/