Apache Xalan-C++ 在 Ubuntu 22.04 集成使用指南
在 Ubuntu 22.04 从零集成 Apache Xalan-C++ 1.12:apt 装 Xerces-C++ 依赖、源码 CMake 构建安装、CLI 首次转换、C++ API 最小示例编译运行、运行时链接与 pkg-config 全链路实测,含生命周期作用域与告警豁免等实战要点。
Apache Xalan-C++ 在 Ubuntu 22.04 集成使用指南
目标:在 Ubuntu 22.04 服务器上从零到一完成 Apache Xalan-C++ 1.12 的集成:装依赖、源码构建安装、命令行跑通第一次 XSLT 转换、手写 C++ API 最小示例并编译运行,最后交代运行时链接、pkg-config 与生命周期作用域三个工程落地要点。本文全部命令与回显均在真实环境逐条实测通过。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(x86_64) |
| 编译器 | gcc/g++ 11.4.0(Ubuntu 11.4.0-1ubuntu1~22.04.3) |
| 构建系统 | cmake 3.22.1 |
| XML 解析器 | Xerces-C++ 3.2.3+debian-3ubuntu0.1(apt 官方仓库) |
| ICU | 70.1(系统自带) |
| Xalan-C++ | 1.12(官方源码包构建,Release) |
| 实验目录 | /root/xalan_c-1.12(源码)、/root/xalan_c-1.12-build(构建)、/root/xalanc-demo(示例) |
| 管理账号 | root(密码 q1w2e3r4) |
工具链版本实测回显(gcc --version、cmake --version、dpkg -l | grep xerces):
gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
cmake version 3.22.1
libxerces-c-dev:amd64 3.2.3+debian-3ubuntu0.1
libxerces-c3.2:amd64 3.2.3+debian-3ubuntu0.1
💡 技术拓展:Ubuntu 22.04 官方仓库没有 xalan-c 运行库包(只有 Xerces-C++ 的 -dev 包),所以 Xalan-C++ 必须源码构建。这也是本文以源码为主线的原因;apt 能解决的只有依赖部分。
二、安装依赖与获取源码
2.1 安装编译依赖
apt-get update
apt-get install -y build-essential cmake libxerces-c-dev
三件套的作用:build-essential 提供 gcc/g++/make,cmake 提供 1.12 要求的构建入口,libxerces-c-dev 提供 Xalan 构建必需的解析器头文件与 so。
2.2 下载源码包并校验
cd /root
wget https://archive.apache.org/dist/xalan/xalan-c/sources/xalan_c-1.12.tar.gz
sha256sum xalan_c-1.12.tar.gz
实测回显:
ee7d4b0b08c5676f5e586c7154d94a5b32b299ac3cbb946e24c4375a25552da7 xalan_c-1.12.tar.gz
包体积实测 1,130,924 字节(约 1.1 MB)。
2.3 解压
tar xzf xalan_c-1.12.tar.gz
解压出的顶层目录是 xalan_c-1.12(带下划线),与包名一致:
xalan_c-1.12/
xalan_c-1.12/CMakeLists.txt
xalan_c-1.12/CREDITS
...
💡 技术拓展:老版本 Xalan-C++ 的源码目录带连字符(xalan-c-1.11),1.12 改成了下划线。写自动化脚本时不要凭印象拼写,先
tar tzf看一眼顶层目录名。
三、CMake 配置与编译安装
3.1 配置
mkdir xalan_c-1.12-build && cd xalan_c-1.12-build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ../xalan_c-1.12
实测配置输出(保留关键行):
-- Found the following ICU libraries:
-- uc (required)
-- data (required)
-- i18n (required)
-- Found ICU: /usr/include (found version "70.1")
-- Found XercesC: /usr/lib/x86_64-linux-gnu/libxerces-c.so (found suitable version "3.2.3", minimum required is "3.1")
-- Performing Test XALAN_HAVE_STD_THREAD
-- Performing Test XALAN_HAVE_STD_THREAD - Success
--
-- Xalan-C++ configuration summary
-- -------------------------------
--
-- Version: 1.12.0
-- Library major version: 112
-- Library minor version: 0
--
-- Installation directory: /usr/local
-- C compiler: /usr/bin/cc
-- C++ compiler: /usr/bin/c++
--
-- Build shared libraries: ON
-- Thread implementation: standard
-- Transcoder: icu
-- Message Loader: inmemory
-- Message Loader Locale: en_US
-- Configuring done
-- Generating done
-- Build files have been written to: /root/xalan-c-1.12-build
四个关键配置项的默认值与含义(构建期可改,逐项实测对照见《Apache Xalan-C++ 1.12 配置参数详解》):
| 配置项 | 实测默认 | 说明 |
|---|---|---|
| thread | standard | std::thread 可用时的默认值;备选 posix |
| transcoder | icu | 检测到 ICU 时默认 icu,否则 default |
| message-loader | inmemory | 消息编进库内;nls/icu 两个变体上游标注 broken |
| message-locale | en_US | 实测仅此一个 locale 可选 |
3.2 编译
make -j12
实测结果:编译全程零错误,GCC 11 产生的告警全部是 -Wdeprecated-copy(集中在 src/xalanc/Include/XalanList.hpp 的迭代器实现),末尾正常收尾:
[100%] Built target Threads
[100%] Linking CXX executable Conf
[100%] Built target TestXPath
[100%] Built target Conf
[100%] Linking CXX executable Performance
[100%] Built target Performance
💡 技术拓展:如果项目构建体系把
-Werror设为全局默认,引入 Xalan 头文件的编译单元会因-Wdeprecated-copy直接失败。工程上无需改 Xalan 源码,给包含路径加告警豁免即可(GCC 语法:-isystem /usr/local/include替代-I,系统头路径默认不报此类告警)。
3.3 安装与产物清单
make install
安装后的文件分布(实测 ls 结果):
/usr/local/bin/Xalan
/usr/local/lib/libxalan-c.so -> libxalan-c.so.112
/usr/local/lib/libxalan-c.so.112 -> libxalan-c.so.112.0
/usr/local/lib/libxalan-c.so.112.0 (5,761,640 字节)
/usr/local/lib/libxalanMsg.so -> libxalanMsg.so.112
/usr/local/lib/libxalanMsg.so.112 -> libxalanMsg.so.112.0
/usr/local/lib/libxalanMsg.so.112.0 (55,280 字节)
/usr/local/lib/pkgconfig/xalan-c.pc
/usr/local/include/xalanc/ (15 个子目录)
执行 ldconfig 刷新动态库缓存后,Xalan 命令即可全局使用:
ldconfig
which Xalan
/usr/local/bin/Xalan
四、命令行第一次转换
4.1 准备测试数据
在 /root/xalanc-demo 下创建一份学生成绩单 XML 与对应样式表:
mkdir -p /root/xalanc-demo && cd /root/xalanc-demo
hello.xml:
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="2026001">
<name>Alice</name>
<score>92</score>
</student>
<student id="2026002">
<name>Bob</name>
<score>85</score>
</student>
<student id="2026003">
<name>Charlie</name>
<score>78</score>
</student>
</students>
hello.xsl(含一个可被参数覆盖的及格线 $passLine,默认 80):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:param name="passLine" select="80"/>
<xsl:template match="/students">
<html>
<body>
<h2>Score Report</h2>
<table border="1">
<tr><th>ID</th><th>Name</th><th>Score</th><th>Result</th></tr>
<xsl:apply-templates select="student"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="student">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="score"/></td>
<td>
<xsl:choose>
<xsl:when test="score >= $passLine">PASS</xsl:when>
<xsl:otherwise>FAIL</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
4.2 执行转换
Xalan hello.xml hello.xsl
实测输出(HTML 直接打到标准输出):
<html>
<body>
<h2>Score Report</h2>
<table border="1">
<tr>
<th>ID</th><th>Name</th><th>Score</th><th>Result</th>
</tr>
<tr>
<td>2026001</td><td>Alice</td><td>92</td><td>PASS</td>
</tr>
<tr>
<td>2026002</td><td>Bob</td><td>85</td><td>PASS</td>
</tr>
<tr>
<td>2026003</td><td>Charlie</td><td>78</td><td>FAIL</td>
</tr>
</table>
</body>
</html>
Alice 92、Bob 85 高于默认及格线 80 记 PASS,Charlie 78 记 FAIL,判定逻辑正确。CLI 全部参数的逐项实测(-o/-t/-p/-e/-i/-a/-v/stdin 等)见《Apache Xalan-C++ 1.12 常用 CLI 命令与工具详解》。
五、C++ API 最小示例:编译到运行
5.1 示例代码
/root/xalanc-demo/api/simple_transform.cpp(实测可编译运行,全文如下):
#include <xalanc/Include/PlatformDefinitions.hpp>
#include <iostream>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xalanc/XalanTransformer/XalanTransformer.hpp>
#include <xalanc/XSLT/XSLTInputSource.hpp>
#include <xalanc/XSLT/XSLTResultTarget.hpp>
using namespace std;
using namespace xercesc;
using namespace xalanc;
int
main(int argc, char* argv[])
{
if (argc != 4)
{
cerr << "Usage: " << argv[0] << " <xml-file> <xsl-file> <out-file>" << endl;
return 1;
}
// 初始化 Xerces 与 Xalan 运行时
XMLPlatformUtils::Initialize();
XalanTransformer::initialize();
{
XalanTransformer theTransformer;
// 源文档与样式表经 XSLTInputSource 包装,结果写入 XSLTResultTarget
XSLTInputSource xmlSource(argv[1]);
XSLTInputSource xslSource(argv[2]);
XSLTResultTarget resultTarget(argv[3]);
const int theResult =
theTransformer.transform(xmlSource, xslSource, resultTarget);
if (theResult != 0)
{
cerr << "transform() failed: "
<< theTransformer.getLastError() << endl;
}
else
{
cout << "Transform OK -> " << argv[3] << endl;
}
}
// 释放运行时
XalanTransformer::terminate();
XMLPlatformUtils::Terminate();
XalanTransformer::ICUCleanUp();
return 0;
}
5.2 编译
cd /root/xalanc-demo/api
g++ -std=c++14 simple_transform.cpp -o simple_transform \
-I/usr/local/include -lxalan-c -lxalanMsg -lxerces-c
echo "compile exit=$?"
实测:
compile exit=0
-rwxr-xr-x 1 root root 31104 Oct 16 00:28 simple_transform
链接三件套缺一不可:-lxalan-c 是引擎、-lxalanMsg 是消息库(Xalan 内部抛异常会引用它)、-lxerces-c 是解析器。
5.3 运行
./simple_transform ../hello.xml ../hello.xsl out.html
echo "exit=$?"
cat out.html
实测输出:
Transform OK -> out.html
exit=0
<html>
<body>
<h2>Score Report</h2>
<table border="1">
<tr>
<th>ID</th><th>Name</th><th>Score</th><th>Result</th>
</tr>
<tr>
<td>2026001</td><td>Alice</td><td>92</td><td>PASS</td>
</tr>
<tr>
<td>2026002</td><td>Bob</td><td>85</td><td>PASS</td>
</tr>
<tr>
<td>2026003</td><td>Charlie</td><td>78</td><td>FAIL</td>
</tr>
</table>
</body>
</html>
5.4 API 调用四步曲(必须遵守的顺序)
| 步骤 | 调用 | 说明 |
|---|---|---|
| 1 | XMLPlatformUtils::Initialize() | Xerces 运行时先初始化 |
| 2 | XalanTransformer::initialize() | Xalan 全局初始化(只调一次) |
| 3 | { XalanTransformer t; ... } | 内层作用域内创建实例并做全部变换 |
| 4 | terminate() → Terminate() → ICUCleanUp() | 按此顺序释放 |
第 3 步的内层作用域不是风格问题,是崩溃防线:XalanTransformer 的析构会释放内存池,若把实例声明在 main 顶层(无内层作用域),析构时机会晚于 XalanTransformer::terminate(),实测必现段错误(exit 139,复现与规避见《Apache Xalan-C++ 1.12 配置参数详解》生命周期一节)。
六、运行时链接与 pkg-config
6.1 pkg-config 使用与已知瑕疵
pkg-config xalan-c --cflags --libs
实测:
-I/usr/local/include -L/usr/local/lib -lxalan-c
坑:这个 .pc 文件的 Version 字段是空的(实测 pkg-config --modversion xalan-c 返回空串,.pc 内容里 Version: 后面什么都没有)。Makefile 里用 pkg-config --modversion xalan-c 做版本判断会拿到空值。版本检测改读头文件宏:
grep -E "XALAN_VERSION_(MAJOR|MINOR|REVISION)" /usr/local/include/xalanc/Include/XalanVersion.hpp | head -3
#define XALAN_VERSION_MAJOR (1)
#define XALAN_VERSION_MINOR (12)
#define XALAN_VERSION_REVISION (0)
另一个发现:Xerces 在 Ubuntu 22.04 上没有提供 xerces-c.pc(实测 pkg-config xerces-c 报不存在),链接 Xerces 只能手写 -lxerces-c。
6.2 Makefile 模板(实测可用)
CXXFLAGS += -std=c++14 $(shell pkg-config xalan-c --cflags)
LIBS += $(shell pkg-config xalan-c --libs) -lxalanMsg -lxerces-c
simple_transform: simple_transform.cpp
$(CXX) $(CXXFLAGS) $< -o $@ $(LIBS)
注意模板里补了 -lxalanMsg -lxerces-c:xalan-c.pc 的 Libs 行只带 -lxalan-c,另两个库需要自己补。
七、构建产物自测与样例
7.1 ctest 全量自测
构建目录里直接跑(安装后不影响):
cd /root/xalan-c-1.12-build && ctest
实测末尾:
100% tests passed, 0 tests failed out of 21
Total Test time (real) = 0.26 sec
21 项测试覆盖 16 个官方样例(TraceListen 有 4 种模式各算一项,SimpleXPathAPI 有两组参数)。选型或升级验证时,ctest 全绿是最快的健康检查。
7.2 16 个样例的构建产物位置
ls /root/xalan-c-1.12-build/samples/
实测清单:CompileStylesheet、DocumentBuilder、EntityResolver、ExternalFunction、ParsedSourceWrappers、SerializeNodeSet、SimpleTransform、SimpleXPathAPI、SimpleXPathCAPI、StreamTransform、ThreadSafe、TraceListen、TransformToXercesDOM、UseStylesheetParam、XalanTransform、XalanTransformerCallback。各样例在自己的源码目录下运行(工作目录里有配套 foo.xml/foo.xsl 测试数据)。
八、卸载与清理
Xalan-C++ 没有独立 uninstall 目标(实测 make help 目标列表无 uninstall)。/usr/local 手工安装的清理即删除三类文件:
rm -f /usr/local/bin/Xalan /usr/local/lib/libxalan-c.so* /usr/local/lib/libxalanMsg.so* /usr/local/lib/pkgconfig/xalan-c.pc
rm -rf /usr/local/include/xalanc
ldconfig
⚠️ 注意:
rm -f /usr/local/lib/libxalan-c.so*不会误删 libxerces-c(名字不同),但别把通配写成libxalan*——libxalanMsg 也在同一前缀下,那正是要删的;如果当初改过 CMAKE_INSTALL_PREFIX,按实际前缀清理。
九、注意事项与常见问题
Q1:cmake 报 Xerces 版本不满足?
确认 libxerces-c-dev 已安装且版本 ≥ 3.1(实测 22.04 仓库为 3.2.3,直接满足)。自编译 Xerces 时注意 make install 后执行 ldconfig。
Q2:编译业务代码报 xalanc/Include/PlatformDefinitions.hpp: No such file?
没加 -I/usr/local/include。用 pkg-config --cflags 代替手写路径可避免。
Q3:链接报 undefined reference to xalanc_1_12::XalanTransformer::initialize()?
链接顺序问题:把 -lxalan-c -lxalanMsg -lxerces-c 放在源文件之后;或漏了 -lxalanMsg(消息库被引擎引用)。
Q4:运行时报找不到 libxalan-c.so.112?
装完没跑 ldconfig,或安装到了非默认前缀但没配 LD_LIBRARY_PATH。
Q5:程序段错误(exit 139)?
九成是 Transformer 生命周期问题:实例析构晚于 terminate()。把 XalanTransformer 放进内层 { } 作用域,全部变换完成后先出作用域再 terminate。
Q6:编译时满屏 deprecated-copy 告警?
GCC 11 对 XalanList.hpp 老式迭代器写法的提示,无错误、不影响运行。洁癖方案:包含路径用 -isystem 替代 -I。
十、参考链接
- Xalan-C++ 官方主页:https://xalan.apache.org/xalan-c/
- 源码下载:https://archive.apache.org/dist/xalan/xalan-c/sources/xalan_c-1.12.tar.gz
- Xerces-C++ 下载页:https://xerces.apache.org/xerces-c/download.cgi
- 本专栏相关文档:《Apache Xalan-C++ 介绍与选型指南》《Apache Xalan-C++ 1.12 配置参数详解》《Apache Xalan-C++ 1.12 常用 CLI 命令与工具详解》