Apache Xerces-C++ 介绍与选型指南
解析 Apache Xerces-C++ 3.3.0 的定位、SAX/SAX2/DOM 解析体系、与 Xerces-J/libxml2/pugixml 的选型对比,已在 Ubuntu 22.04 上源码编译并实测全部样例程序。
Apache Xerces-C++ 介绍与选型指南
目标:讲清 Apache Xerces-C++ 是什么、提供哪些解析 API、适合什么场景,并给出与 Xerces-J、libxml2、pugixml 的选型对比依据。文中版本号、编译摘要、样例程序清单均在 Ubuntu 22.04 服务器上实测取得(源码编译 Xerces-C++ 3.3.0 + apt 对照 3.2.3)。
一、环境信息
本文所有实测在以下环境完成,读者复核时可按相同配置搭建。
- 操作系统:Ubuntu 22.04(GNU/Linux x86_64)
- 编译器:gcc/g++ 11.4.0(Ubuntu 11.4.0-1ubuntu1~22.04.3)
- 构建工具:cmake 3.22.1
- 主角版本:Xerces-C++ 3.3.0(官方源码包 xerces-c-3.3.0.tar.gz,7,568,765 字节,sha256 前缀
9555f1d0) - 对照版本:Ubuntu 22.04 仓库 libxerces-c-dev 3.2.3+debian-3ubuntu0.1
- 源码包官方地址:https://dlcdn.apache.org/xerces/c/3/sources/xerces-c-3.3.0.tar.gz
实测取得的版本证据如下。先在官网确认 3.3.0 为当前稳定版,再下载校验:
curl -s https://xerces.apache.org/xerces-c/ | grep -oE "Xerces-C\+\+ [0-9.]+"
curl -s -o xerces-c-3.3.0.tar.gz https://dlcdn.apache.org/xerces/c/3/sources/xerces-c-3.3.0.tar.gz
sha256sum xerces-c-3.3.0.tar.gz
实测输出(Ubuntu 22.04 服务器):
Xerces-C++ 3.3.0
9555f1d06f82987fbb4658862705515740414fd34b4db6ad2ed76a2dc08d3bde xerces-c-3.3.0.tar.gz
apt 仓库侧的对照版本(同一台服务器实测):
$ apt-cache policy libxerces-c-dev
libxerces-c-dev:
Installed: (none)
Candidate: 3.2.3+debian-3ubuntu0.1
Version table:
3.2.3+debian-3ubuntu0.1 500
500 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages
500 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages
关键差异解读:官网最新稳定版为 3.3.0(仅源码分发,无 Linux 官方二进制包);Ubuntu 22.04 仓库停留在 3.2.3+debian,比官方最新版落后一个版本,且库接口版本不同(3.3.0 的库文件为 libxerces-c-3.3.so,3.2.3 为 libxerces-c-3.2.so)。选型时要意识到这条版本差,具体编译安装见《Apache Xerces-C++ 在 Ubuntu 22.04 集成使用指南》。
二、软件概述
Xerces-C++ 是 Apache 软件基金会官方的 XML 校验解析器,用「可移植的 C++ 子集」编写(刻意少用模板、少用 #ifdef,便于移植到各类平台与老编译器)。它以共享库的形式提供 XML 文档的解析、生成、操作与校验能力,暴露 DOM、SAX、SAX2 三套编程 API。
本节信息全部来自官网首页原文(xerces.apache.org/xerces-c/,2026-10 抓取),要点如下:
- 定位:faithful to the XML 1.0 recommendation and many associated standards——严格遵循 XML 1.0 推荐标准及多项关联标准;
- 交付形态:3.3.0 仅提供源码分发("available as a source distribution only"),无官方 Linux 二进制包;
- 许可证:Apache Software License, Version 2.0;
- 旧版本警示:Xerces 2.8.0 及更早版本 100% 不再支持("100% unsupported"),仍在使用的应用应迁移到 3.x;
- 维护状态警示(选型必读):官网明示 "Xerces-C++ currently lacks active maintainers and therefore may not be able to promptly address all bugs and security risks"——当前缺乏活跃维护者,bug 与安全风险的修复可能不及时。这意味着选型时需自行评估安全兜底能力(如订阅 c-dev 邮件列表、准备本地补丁能力)。
2.1 版本线与命名辨析
Xerces 家族容易混淆,实测官网口径整理如下:
| 名称 | 语言 | 当前状态 | 说明 |
|---|---|---|---|
| Xerces-C++ 3.3.0 | C++ | 官网最新稳定版 | 本文主角,库接口版本 3.3 |
| Xerces-J | Java | 同一 Xerces 项目下并行的 Java 实现 | API 风格与 Xerces-C++ 同源,类名几乎一一对应 |
| Xerces 2.8.0 及更早 | C++/Perl 等 | 100% 不支持 | 官网明示不应再用于新应用 |
| Xerces-P(XML::Xerces) | Perl | 绑定层 | 基于 Xerces-C++ 的 SWIG 绑定 |
💡 技术拓展:C++ 标准库里没有 XML 解析器,因此「解析器库选型」是 C++ 工程的必答题。同类主流选项一览见第六章对比表;此处先给一句话结论——Xerces-C++ 是「校验能力最全、标准遵循最严」的一档,代价是库体积与内存占用偏大。
三、核心架构
3.1 解析 API 体系:SAX / SAX2 / DOM
Xerces-C++ 对外提供三套 API,实测 3.3.0 源码头文件目录与三者一一对应(/usr/local/include/xercesc/ 下实测目录为 dom、framework、internal、parsers、sax、sax2、util、validators、xinclude):
| API | 处理模型 | 内存特征 | 典型用途 |
|---|---|---|---|
| SAX 1.0 | 事件推送(push) | 极低,流式 | 大文件扫描、提取片段 |
| SAX2 | 事件推送 + namespace 支持 + 特性开关 | 极低,流式 | 大文件、带命名空间文档 |
| DOM(DOM Level 1/2/3 Core + Load and Save) | 全量建树 | 与文档大小成正比 | 随机访问、修改、序列化回写 |
💡 技术拓展:XML 解析的两大流派是「推送式(Push)」与「拉取式(Pull)」。SAX 是推送式——解析器边读边把 startElement/characters/endElement 事件推给你的 Handler,程序被动接事件,内存占用小但写法是回调式的;拉取式(如 StAX 之于 Java、pugixml 的迭代风格)由程序主动向解析器要下一个事件,控制流更直观。Xerces-C++ 主体是推送式 SAX + 全量 DOM;另外它还有一个渐进解析入口(扫描到目标即停),实测样例 PParse 就是用
scanFirst()/scanNext()演示"读到 16 个元素就退出"的能力。
3.2 两大解析器入口与校验管线
按 API 选择解析器类:SAX2 用 SAX2XMLReader(由工厂 XMLReaderFactory::createXMLReader() 创建),DOM 用 XercesDOMParser(另有 DOM Level 3 的 DOMLSParser)。两者共用同一套校验内核(validators/ 目录),支持 DTD 与 XML Schema(XSD)两种校验方式,校验开关通过 setFeature(特性,布尔开关)与 setProperty(属性,值型配置)控制——全部参数逐项实测见《Apache Xerces-C++ 3.3.0 配置参数详解》。
内置字符串类型是理解这套库的第一道门槛:Xerces-C++ 内部统一用 XMLCh 存储字符,3.x 里 XMLCh 就是 C++11 的 char16_t(UTF-16 编码单元)。因此 API 出入参都是 const XMLCh*,与 char* 之间必须用 XMLString::transcode()/release() 显式互转,这也是编译期最常见的报错来源。实测在 3.3.0 下把 char* 直接传给 getFeature() 的编译报错(节选):
error: cannot convert 'char*' to 'const XMLCh*' {aka 'const char16_t*'}
135 | virtual bool getFeature(const XMLCh* const name) const = 0;
完整转码写法与陷阱(release 必须成对、否则内存泄漏)在《Apache Xerces-C++ 在 Ubuntu 22.04 集成使用指南》有逐行实测。
3.3 平台适配层:可插拔组件
源码 CMake 配置摘要(Ubuntu 22.04 实测)显示 Xerces-C++ 内部有四个可插拔平台组件,均可通过 CMake 选项替换:
-- Xerces-C++ configuration summary
-- --------------------------------
--
-- Version: 3.3.0
-- Library interface version: 3.3
--
-- Installation directory: /usr/local
-- C compiler: /usr/bin/cc
-- C++ compiler: /usr/bin/c++
--
-- Build shared libraries: ON
-- Path delimiters: "/"
-- File Manager: POSIX
-- Mutex Manager: standard
-- Transcoder: gnuiconv
-- NetAccessor: socket
-- Message Loader: inmemory
-- XMLCh type: char16_t
- Transcoder(转码器):外部编码 ↔ UTF-16 的转换实现。默认
gnuiconv(glibc iconv),可选iconv、icu(需 ICU 库)等; - Message Loader(消息加载器):错误消息文本来源。默认
inmemory(编译进库,开箱即用),可选iconv(运行期读 .cat 目录文件)、msgcatalog(系统 catopen/gettext 类目录)。实测把 message-loader 换成iconv后库能编译安装,但运行时因找不到XercesMessages_en_US.cat直接退出(Cannot load message domain,exit=255)——生产环境保持默认inmemory最稳; - NetAccessor(网络访问器):解析时拉取远程 DTD/Schema 的实现,默认
socket,可关(-Dnetwork=OFF)或换curl; - File Manager / Mutex Manager:文件访问与互斥锁实现,Linux 上默认 POSIX/standard,一般不动。
这四个组件的 CMake 选项逐项实测与换装代价见《Apache Xerces-C++ 3.3.0 配置参数详解》。
3.4 同一文档在 SAX2 与 DOM 下的实测行为差异
为直观对比两套 API,用同一个 notes.xml(2 个 note 子元素、共 9 个元素节点、2 个属性)分别跑自写的 SAX2 计数程序与 DOM 遍历程序(完整源码与编译见《Apache Xerces-C++ 在 Ubuntu 22.04 集成使用指南》):
./sax2_count notes.xml # SAX2 事件流计数
./dom_parse notes.xml # DOM 建树后遍历
实测输出:
$ ./sax2_count notes.xml
elements=9 attributes=2 characters=89
$ ./dom_parse notes.xml
root element: notes
note count: 2
note[0] id=1 to=Alice
note[1] id=2 to=Carol
行为差异一目了然:SAX2 只给"事件账本"(9 个元素、2 个属性、89 个字符),不保留任何结构,程序退出即释放;DOM 则保留整棵树,程序可以按任意顺序随机访问(本例按 id 取属性、按子元素名取文本)。格式不良文档在两种 API 下的报错位置也完全一致(行 6 列 3 的未闭合标签),说明两者共用同一套扫描与校验内核。
另一个实测细节是库的运行时绑定:编译产物只依赖一个 Xerces 库文件,ldd 实测:
$ ldd ./sax2_count | grep xerces
libxerces-c-3.3.so => /usr/local/lib/libxerces-c-3.3.so (0x0000715221a6f000)
单一共享库、无强制 ICU 等第三方依赖,这使 Xerces-C++ 在部署面(拷贝一个 .so)上比很多重型 C++ 库更简单。
四、功能特性
以下特性清单来自官网原文,并标注本文实测情况:
| 特性 | 官网口径 | 本文实测 |
|---|---|---|
| XML 1.0(Third Edition)/ XML 1.1 | 遵循(1.1 的 2.13 规范化检查未实现) | 1.0 文档解析正常(样例全通过) |
| DOM Level 1/2/3 Core、DOM L3 Load and Save | 遵循 | XercesDOMParser 建树/遍历/取属性实测通过 |
| SAX 1.0 / SAX 2.0 | 遵循 | SAX2 计数、错误处理器实测通过 |
| Namespaces in XML 1.0/1.1 | 遵循 | SAX2Reader namespaces 特性默认开启(getFeature 实测 true) |
| XML Schema Part 1/2(2001 推荐标准) | 遵循 | XSD 校验实测:非法值触发 ERROR(value 'thirty' does not match regular expression facet '[+\-]?[0-9]+') |
| XInclude 1.0(Second Edition) | 遵循 | 官方样例 XInclude 实测:xi:include 展开成功并生成 xml:base |
| Element Traversal | 遵循 | 未单独测 |
| 程序化生成与校验 XML | 支持 | CreateDOMDocument 样例实测(内存建树 4 元素) |
| 可插拔 catalog/validator/encoding | 支持 | CMake 组件层实测(见 3.3) |
| 自定义错误处理 | 支持 | ErrorHandler 三级回调(warning/error/fatalError)实测 |
实测中的校验行为示例(SAX2 + 外部 XSD,Ubuntu 22.04):对 <age>thirty</age> 的实例文档校验,自定义 ErrorHandler 捕获到:
ERROR | /root/xtest/employee_bad.xml:5:20 | value 'thirty' does not match regular expression facet '[+\-]?[0-9]+'
parse done: warnings=0 errors=1 fatals=0
而格式不良文档(未闭合标签)触发 fatalError 并中断解析:
FATAL | /root/xtest/bad1.xml:6:3 | expected end of tag 'body'
parse aborted by fatalError: warnings=0 errors=5 fatals=1
两者的分级语义(error 不中断、fatalError 默认中断、可配 continue-after-fatal-error 继续)在配置参数详解篇有逐项开关实测。
4.1 随源码分发的样例程序清单
3.3.0 源码包自带 16 个样例程序,实测 make 后全部编译成功并随 make install 落到 /usr/local/bin:
CreateDOMDocument DOMCount DOMPrint EnumVal MemParse
PParse PSVIWriter Redirect SAX2Count SAX2Print
SAXCount SAXPrint SCMPrint SEnumVal StdInParse XInclude
这组样例既是官方用法示范,也是一套现成的命令行 XML 工具(SAXCount 数元素、DOMPrint 格式化输出、SEnumVal 枚举 Schema 组件等),逐参数实测见《Apache Xerces-C++ 常用 CLI 命令与工具详解》。
4.2 官方样例工具的即战力实测
把样例当 CLI 工具用是 Xerces-C++ 的隐藏福利。同一份带 DTD 的 personal.xml(37 元素、12 属性),几个典型工具的实测输出:
$ SAXCount -v=always personal.xml
personal.xml: 1 ms (37 elems, 12 attrs, 134 spaces, 134 chars)
$ DOMCount -v=always -s -n personal-schema.xml
personal-schema.xml: 1 ms (37 elems).
$ DOMPrint -wenc=UTF-8 -wfpp=on personal.xml # 前 5 行
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE personnel SYSTEM "personal.dtd">
<!-- @version: -->
<personnel>
<person id="Big.Boss">
$ MemParse # 内存缓冲解析 + DTD 内联校验
Parsing took 0 ms (4 elements, 1 attributes, 16 spaces, 95 characters).
实测观察:小文件解析均在毫秒级;SAXCount/DOMCount 统计口径不同(DOMCount 只数元素);DOMPrint 自带 pretty-print 与输出编码切换。这也侧面验证了架构章的说法——所有样例共用同一校验内核,只是 Handler 侧形态不同。
4.3 多版本共存实测(3.3.0 与 3.2.3 并行)
在同一台 Ubuntu 22.04 上实测「源码版 3.3.0(/usr/local)+ 仓库版 3.2.3(apt)」共存,动态链接器同时注册两个 soname:
$ ldconfig -p | grep -i xerces
libxerces-c-3.3.so (libc6,x86-64) => /usr/local/lib/libxerces-c-3.3.so
libxerces-c-3.2.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libxerces-c-3.2.so
但头文件与库必须严格同版本:Xerces-C++ 的 C++ 符号命名空间带版本号(xercesc_3_3/xercesc_3_2),实测用 3.3 头文件编译、错误地链接到 3.2 库时,直接产生大量 undefined reference to xercesc_3_3::... 链接错误;按正确姿势(独立前缀 + pkg-config 指定路径)两版程序可各自编译运行。完整实测矩阵与正确做法见《Apache Xerces-C++ 在 Ubuntu 22.04 集成使用指南》的多版本共存一节。
五、适用场景与限制
适合选 Xerces-C++ 的场景(官网 "Applications of the Xerces Parser" 原文 + 实测补充):
- 需要严格校验的 XML 处理:DTD + XML Schema 双校验、full schema constraint checking 开关,适合电子数据交换、报表规范、配置校验;
- 国际化应用:内置多编码转码(UTF-8/UTF-16/ISO8859-1/GBK 等经转码器支持)、XMLCh 统一 UTF-16 内部表示;
- 需要 DOM 读写回写:DOM L3 Load and Save 支持解析后修改再序列化;
- 跨平台 C++ 项目:官方覆盖 Linux/Windows/macOS 等多平台,源码可移植性是设计目标;
- 与 Xerces-J 保持 API 同构:同一套 XML 处理逻辑要在 Java 与 C++ 服务间对齐心智成本最低(类名、异常、feature URI 基本一致)。
限制与代价(选型前必须接受):
- 维护状态:官网明示缺乏活跃维护者,安全修复不及时的风险需自行兜底;
- 体积与内存:动态库实测 5.1 MB(
libxerces-c-3.3.so5,163,280 字节),DOM 建树内存与文档大小成正比,大文件场景不如流式方案友好; - 仅源码分发:3.3.0 无官方 Linux 二进制包,发行版仓库版本通常滞后(Ubuntu 22.04 为 3.2.3+debian),需要自编译能力;
- XMLCh 类型摩擦:所有 API 用
char16_t,与std::string生态对接都要转码,工程里容易写漏 release 造成泄漏; - 错误消息本地化:默认 inmemory 消息加载器输出英文消息,切换本地化消息目录有额外部署成本(实测 iconv 目录文件未随 install 就位导致运行失败)。
六、同类选型对比
C++ XML 解析器主流可选项如下表(均为业界常见实现,实测数据栏为本文在 Ubuntu 22.04 的实测值):
| 库 | 校验能力 | API | 内存模型 | 依赖 | 许可证 | 本文实测要点 |
|---|---|---|---|---|---|---|
| Xerces-C++ 3.3.0 | DTD + XML Schema 1.0(最全) | SAX/SAX2/DOM L3 | 流式或全树 | 无强制外部依赖 | Apache-2.0 | 16 个样例全编译通过;XSD 校验实测生效 |
| Xerces-J | DTD + XML Schema 1.0/1.1 | SAX/DOM/StAX(JAXP) | JVM 堆 | JVM | Apache-2.0 | 与 Xerces-C++ 同项目,API 同构,Java 技术栈直接选它 |
| libxml2 | DTD + XML Schema + RelaxNG + Schematron | SAX/tree(push/pull) | 流式或全树 | zlib 等可选 | MIT | Linux 发行版事实标准(systemd/GLib 生态依赖),C 接口为主 |
| pugixml | 无 schema 校验(仅格式与 DTD 弱支持) | 自有 DOM + XPath | 全树(极快) | 无 | MIT | 单小库,导入导出快,适合配置文件级数据 |
| expat | 仅格式良构校验,不校验 DTD 外部子集 | SAX 流式 | 流式 | 无 | MIT | 极小极快,适合只做格式解析的嵌入场景 |
💡 技术拓展:上表「校验能力」一栏是选型分水岭——良构(well-formed)只保证语法合法(标签闭合、嵌套正确),有效(valid)才保证符合 DTD/XSD 声明的结构与数据类型。expat/pugixml 面向良构,Xerces-C++/libxml2 面向有效;业务要求"age 必须是整数、id 必填"这类规则时就只能选后者。
关键差异与选型建议(结合实测):
- C++ 技术栈 + 重校验(B2B 数据交换、行业标准报文、XML 编辑器内核)→ Xerces-C++:校验最全、标准遵循最严,本文实测其 XSD 数据类型校验可精确报出
regular expression facet级错误与行列号; - C 技术栈或系统级组件(GNOME 生态、需要 RelaxNG/Schematron)→ libxml2:能力同样完整且是发行版自带依赖,但 API 是 C 风格,C++ 工程封装成本略高;
- 只读配置文件、追求轻快 → pugixml:无校验负担,全树解析性能强、集成成本最低;
- Java 服务 → Xerces-J(JDK 内置解析器的底层实现之一),与 C++ 侧 Xerces-C++ 保持概念一致;
- 嵌入式/超大文件纯流式 → expat 或 Xerces-C++ 的 SAX2(本文实测 SAX2 解析仅计数场景内存恒定)。
与 Xerces-J 的对照(同项目并行实现,选型时关注差异面):
| 维度 | Xerces-C++ 3.3.0 | Xerces-J |
|---|---|---|
| 字符类型 | XMLCh = char16_t,需 transcode 与 char* 互转 | java.lang.String,天然 Unicode |
| 构建/分发 | 仅源码,需自编译 | Maven/Jar,开箱即用 |
| 内存管理 | 手动 new/delete + MemoryManager 可插拔 | JVM GC |
| feature/property URI | 相同的 http://apache.org/xml/features/... 体系 | 相同体系 |
| 版本节奏 | 3.3.0(官网,维护者稀缺) | 与 JDK 生态联动更新更活跃 |
一句话结论:两套 Xerces 是"同名不同姓"的孪生 API,feature/property 的 URI 字符串几乎通用,团队若双栈并存,参数经验可以直接复用;差异集中在内存与字符串模型上,这也是 C++ 侧迁移成本的主要来源。
七、参考链接
- Xerces-C++ 官网与最新版本公告:https://xerces.apache.org/xerces-c/
- 官方下载页(含源码包与校验):https://xerces.apache.org/xerces-c/download.cgi
- 官方编程指南(DOM/SAX2/校验):https://xerces.apache.org/xerces-c/program-3.html
- Apache Xerces 项目总览(含 Xerces-J):https://xerces.apache.org/
- 本文配套实测篇:《Apache Xerces-C++ 在 Ubuntu 22.04 集成使用指南》《Apache Xerces-C++ 3.3.0 配置参数详解》《Apache Xerces-C++ 常用 CLI 命令与工具详解》