Apache Xalan-C++ 在 Ubuntu 22.04 集成使用指南

在 Ubuntu 22.04 从零集成 Apache Xalan-C++ 1.12:apt 装 Xerces-C++ 依赖、源码 CMake 构建安装、CLI 首次转换、C++ API 最小示例编译运行、运行时链接与 pkg-config 全链路实测,含生命周期作用域与告警豁免等实战要点。

Apache XalanApache XalanC/C++XSLTUbuntuUbuntu 22.042026/10/16

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 官方仓库)
ICU70.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 配置参数详解》):

配置项实测默认说明
threadstandardstd::thread 可用时的默认值;备选 posix
transcodericu检测到 ICU 时默认 icu,否则 default
message-loaderinmemory消息编进库内;nls/icu 两个变体上游标注 broken
message-localeen_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 调用四步曲(必须遵守的顺序)

步骤调用说明
1XMLPlatformUtils::Initialize()Xerces 运行时先初始化
2XalanTransformer::initialize()Xalan 全局初始化(只调一次)
3{ XalanTransformer t; ... }内层作用域内创建实例并做全部变换
4terminate() → 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。

十、参考链接

  1. Xalan-C++ 官方主页:https://xalan.apache.org/xalan-c/
  2. 源码下载:https://archive.apache.org/dist/xalan/xalan-c/sources/xalan_c-1.12.tar.gz
  3. Xerces-C++ 下载页:https://xerces.apache.org/xerces-c/download.cgi
  4. 本专栏相关文档:《Apache Xalan-C++ 介绍与选型指南》《Apache Xalan-C++ 1.12 配置参数详解》《Apache Xalan-C++ 1.12 常用 CLI 命令与工具详解》