Apache Xerces-C++ 介绍与选型指南

解析 Apache Xerces-C++ 3.3.0 的定位、SAX/SAX2/DOM 解析体系、与 Xerces-J/libxml2/pugixml 的选型对比,已在 Ubuntu 22.04 上源码编译并实测全部样例程序。

Apache XercesApache XercesC/C++XMLApache2026/10/16

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.0C++官网最新稳定版本文主角,库接口版本 3.3
Xerces-JJava同一 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.so 5,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.0DTD + XML Schema 1.0(最全)SAX/SAX2/DOM L3流式或全树无强制外部依赖Apache-2.016 个样例全编译通过;XSD 校验实测生效
Xerces-JDTD + XML Schema 1.0/1.1SAX/DOM/StAX(JAXP)JVM 堆JVMApache-2.0与 Xerces-C++ 同项目,API 同构,Java 技术栈直接选它
libxml2DTD + XML Schema + RelaxNG + SchematronSAX/tree(push/pull)流式或全树zlib 等可选MITLinux 发行版事实标准(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 必填"这类规则时就只能选后者。

关键差异与选型建议(结合实测):

  1. C++ 技术栈 + 重校验(B2B 数据交换、行业标准报文、XML 编辑器内核)→ Xerces-C++:校验最全、标准遵循最严,本文实测其 XSD 数据类型校验可精确报出 regular expression facet 级错误与行列号;
  2. C 技术栈或系统级组件(GNOME 生态、需要 RelaxNG/Schematron)→ libxml2:能力同样完整且是发行版自带依赖,但 API 是 C 风格,C++ 工程封装成本略高;
  3. 只读配置文件、追求轻快 → pugixml:无校验负担,全树解析性能强、集成成本最低;
  4. Java 服务 → Xerces-J(JDK 内置解析器的底层实现之一),与 C++ 侧 Xerces-C++ 保持概念一致;
  5. 嵌入式/超大文件纯流式 → expat 或 Xerces-C++ 的 SAX2(本文实测 SAX2 解析仅计数场景内存恒定)。

与 Xerces-J 的对照(同项目并行实现,选型时关注差异面):

维度Xerces-C++ 3.3.0Xerces-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++ 侧迁移成本的主要来源。

七、参考链接