Apache Xalan-C++ 1.12 常用 CLI 命令与工具详解
Apache Xalan-C++ 1.12 命令行工具全解:Xalan 命令 10 个选项逐项实测(含 -t 计时分流、-m A/B 对照、-p 的 XPath 语义、退出码 0/254/255 体系),TestXSLT 诊断版二进制差异,TestXPath 自测工具,Conf/Performance 回归工具与 16 个官方样例运行实录。
Apache Xalan-C++ 1.12 常用 CLI 命令与工具详解
目标:把 Xalan-C++ 1.12 自带的所有命令行工具一次讲全——安装版 Xalan 命令的每个选项配实测回显、退出码体系、与构建树里 TestXSLT 诊断版二进制的差异,以及 TestXPath、MsgCreator、Conf/Performance 与 16 个官方样例的运行方式。全部命令与回显均在真实环境逐条实测。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(x86_64) |
| Xalan-C++ | 1.12.0(源码构建安装到 /usr/local,Xerces 3.2.3) |
| 工具来源 | /usr/local/bin/Xalan(安装版)+ /root/xalan-c-1.12-build(构建树工具) |
| 测试数据 | /root/xalanc-demo(hello.xml + hello.xsl 学生成绩单) |
| 管理账号 | root(密码 q1w2e3r4) |
二、工具总览:装完有什么
2.1 安装版 vs 构建树
make install 之后 /usr/local/bin 下只有一个 Xalan:
/usr/local/bin/Xalan
其余工具都留在构建树里(实测 /root/xalan-c-1.12-build 产物清单):
| 工具 | 构建树路径 | 是否随安装 | 用途 |
|---|---|---|---|
| Xalan | (由构建产出并安装) | 是 | 生产用 XSLT 转换命令 |
| TestXSLT | src/xalanc/TestXSLT/TestXSLT | 否 | 诊断版转换命令(选项更多) |
| TestXPath | src/xalanc/TestXPath/TestXPath | 否 | XPath 求值自测 |
| MsgCreator | src/xalanc/Utils/MsgCreator/MsgCreator | 否 | 构建期消息编译器 |
| Conf | Tests/Conf | 否 | 回归测试驱动(需外部测试数据) |
| Performance | Tests/Performance | 否 | 性能基准(需外部测试数据) |
| 16 个样例 | samples/* | 否 | API 用法示范 |
2.2 重要发现:Xalan 与 TestXSLT 是两个二进制
实测比对(md5sum):
299434775bfa05ef0b05098276f5a400 /usr/local/bin/Xalan
d690f4db1b53b769ab27528c50046278 /root/xalan-c-1.12-build/src/xalanc/TestXSLT/TestXSLT
两者 md5 不同、选项集不同。容易踩的坑:源码 TestXSLT.cpp 里写的 -in/-xsl/-out/-param 等长选项,安装版 Xalan 不接受(实测全部回 usage、exit=255):
$ Xalan -in hello.xml -xsl hello.xsl -out /tmp/in_out.html
Xalan version 1.12.0.
Xerces version 3.2.3.
Usage: Xalan [options] source stylesheet
Options:
...(10 项用法列表)
exit=255
而 TestXSLT 接受(实测 -in hello.xml -xsl hello.xsl -out /tmp/tt_out.html exit=0,输出正确 HTML)。需要诊断级选项时用构建树里的 TestXSLT,日常脚本用 Xalan。
三、Xalan 命令详解
3.1 基本信息与帮助全文
Xalan -?
实测全文(-? 与 -h 等价):
Xalan version 1.12.0.
Xerces version 3.2.3.
Usage: Xalan [options] source stylesheet
Options:
-a Use xml-stylesheet PI, not the 'stylesheet' argument
-e encoding Force the specified encoding for the output.
-i integer Indent the specified amount.
-m Omit the META tag in HTML output.
-o filename Write output to the specified file.
-p name expression Sets a stylesheet parameter.
-t Display timing information.
-u Disable escaping of URLs in HTML output.
-? Display this message.
-v Validates source documents.
- A dash as the 'source' argument reads from stdin.
('-' cannot be used for both arguments.)
命令形态:Xalan [options] <源XML> <样式表>。不带 -o 时结果打标准输出。前两行版本横幅可当作最轻量的"装没装好"探针。
3.2 逐参数实测
以下测试数据 hello.xml(3 名学生)与 hello.xsl(method="html",及格线参数 $passLine 默认 80)见《Apache Xalan-C++ 在 Ubuntu 22.04 集成使用指南》第四节。
3.2.1 无选项:结果到标准输出
Xalan hello.xml hello.xsl
实测输出:
<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>
3.2.2 -o:输出到文件
Xalan -o /root/xalanc-demo/report.html hello.xml hello.xsl
echo "exit=$?"
实测 exit=0,report.html 内容与标准输出版本一致(同上表结构)。-o 可以指向 /dev/null 做"只验语法"式干跑。
3.2.3 -t:计时信息(走标准错误)
Xalan -t -o /dev/null hello.xml hello.xsl 1>stdout.txt 2>stderr.txt
echo "exit=$?"; echo "--stderr--"; cat stderr.txt; echo "--stdout--"; cat stdout.txt
实测:
exit=0
--stderr--
Source tree parsing time: 0.228 milliseconds.
Stylesheet compilation time: 0.337 milliseconds.
Transformation time: 0.121 milliseconds.
--stdout--
(空)
💡 技术拓展:-t 的三段耗时(源树解析/样式表编译/变换执行)对性能排查很有用——如果"样式表编译时间"占比高,应该像 CompileStylesheet 样例那样预编译样式表复用(一次编译对多份 XML);如果"源树解析时间"占比高,瓶颈在 XML 大小而非样式复杂度。
3.2.4 -p:设置样式表参数(XPath 语义)
数值参数(无引号直接生效):
Xalan -p passLine 70 hello.xml hello.xsl | grep -E "Charlie|Result"
实测(78 分越过新及格线 70,FAIL 翻 PASS):
<th>ID</th><th>Name</th><th>Score</th><th>Result</th>
<td>2026003</td><td>Charlie</td><td>78</td><td>PASS</td>
字符串参数必须带 XPath 字符串引号。裸字符串实测报错(样式表引用了 $title):
$ Xalan -p title "Q1 Score" -o /dev/null hello.xml api/param_demo.xsl
XPath error: Extra illegal token.
expression = 'Q1 Score' Remaining tokens are: ( 'Score') (Occurred in an unknown entity, at an unknown location.)
XPathParserException: Extra illegal token.
expression = 'Q1 Score' Remaining tokens are: ( 'Score') (Occurred in an unknown entity, at an unknown location.)
exit=255
正确写法(单引号包住字面量,实测输出 title 属性正确注入):
$ Xalan -p title "'Q1 Score'" -o /tmp/pd_cli.xml hello.xml api/param_demo.xsl
exit=0
<?xml version="1.0" encoding="UTF-8"?>
<report title="Q1 Score" threshold="80">
<passed count="2"/>
</report>
💡 技术拓展:C1《Apache Xalan-C++ 1.12 配置参数详解》用 API 路径验证了同一语义(裸串 result=-1、引号串 result=0),并发现顶层参数惰性求值——样式表不引用该参数时,裸字符串错误不会触发。CLI 与 API 共享同一套 XPath 求值器,行为完全一致。
3.2.5 -i:指定缩进空格数
对照实测(cat -A 显示空白符,$ 为行尾):
$ Xalan hello.xml hello.xsl (默认,无缩进)
<html>$
<body>$
<h2>Score Report</h2>$
$ Xalan -i 2 hello.xml hello.xsl (-i 2)
<html>$
<body>$
<h2>Score Report</h2>$
<table border="1">$
-i 只影响 HTML/XML 的缩进排版,不改变内容。-i 0 与默认相同。
3.2.6 -e:强制输出编码
UTF-16 实测(xmlout.xsl 输出 <report count="3"/>):
$ Xalan -e UTF-16 -o /tmp/u16.xml hello.xml xmlout.xsl
exit=0
$ od -c /tmp/u16.xml | head -4
0000000 377 376 < \0 ? \0 x \0 m \0 l \0 \0 v \0
0000020 e \0 r \0 s \0 i \0 o \0 n \0 = \0 " \0
0000040 1 \0 . \0 0 \0 " \0 \0 e \0 n \0 c \0
0000060 o \0 d \0 i \0 n \0 g \0 = \0 " \0 U \0
377 376(0xFF 0xFE)是 UTF-16LE 的 BOM,后续每个字符占双字节,且文件内声明同步变为 encoding="UTF-16",强制编码确实生效。对照默认 XML 输出:
$ Xalan hello.xml xmlout.xsl
<?xml version="1.0" encoding="UTF-8"?><report count="3"/>
如实记录:-e GBK 场景实测未产生可用输出(输出文件为空),GBK 支持取决于转码后端(本环境为 ICU);需要 GBK 时建议先验证,不要默认可用。
3.2.7 -m:省略 HTML 输出的 META 标签(A/B 对照)
用官方 XalanTransform 样例数据(foo.xml + foo.xsl,含 head):
$ Xalan foo.xml foo.xsl | head -4 (默认)
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>s1 foo</title>
$ Xalan -m foo.xml foo.xsl | head -4 (加 -m)
<html>
<head>
<title>s1 foo</title>
</head>
META 行确实被省略。两者 exit 均为 0。
3.2.8 -u:禁用 HTML 输出的 URL 转义
实测命令被正常接受(exit=0),输出与默认一致。该选项只在 HTML 结果含 URL 类属性(href/src)且其中带特殊字符时才有可见差异;演示数据无 URL 属性,属预期。
3.2.9 -a:改用 xml-stylesheet 处理指令定位样式表
准备 pi.xml(内嵌 <?xml-stylesheet type="text/xsl" href="hello.xsl"?>),实测:
Xalan -a pi.xml
输出与 Xalan pi.xml hello.xsl 等效的 HTML(exit=0),命令行上不再写样式表参数。-a 生效时第二个位置参数被忽略。
3.2.10 -v:开启源文档校验
Xalan -v -o /dev/null hello.xml hello.xsl
实测 exit=0(hello.xml 本身合法,校验不报问题)。-v 打开 DTD 校验语义;无 DTD 的文档行为不变。
3.2.11 -(连字符):stdin 作为源文档
cat hello.xml | Xalan - hello.xsl | head -3
实测输出正常 HTML(exit=0)。注意帮助文本的红字约束:'-' 不能同时用于两个参数(样式表没有 stdin 写法)。
3.2.12 -?:帮助(exit=255)
$ Xalan -?
...(帮助全文)
exit=255
帮助与"未知选项"共用同一 usage 输出,退出码都是 255(实测 Xalan --bogus hello.xml hello.xsl 同样打印 usage、exit=255)。
3.3 退出码体系(实测汇总)
| 退出码 | 场景 | 实测触发命令与 stderr 样例 |
|---|---|---|
| 0 | 转换成功 | Xalan hello.xml hello.xsl |
| 254 | 转换失败(解析/加载错误) | 样式表不存在:XML warning: Fatal Error: unable to determine file base pathname (Occurred in an unknown entity, at line 0, column 0.) + SAXParseException: unable to determine file base pathname (...) |
| 254 | 源 XML 非法 | Fatal Error: expected end of tag 'b' (Occurred in entity 'bad.xml', at line 1, column 9.) + SAXParseException: ... |
| 255 | 用法错误/帮助/-p 的 XPath 表达式错误 | 未知选项、-?、裸字符串参数的 XPath error: Extra illegal token |
脚本化使用建议:Xalan ... || { case $? in 254) ...文档问题...;; 255) ...调用方式问题...;; esac; }——254 提示去修数据,255 提示去修命令。
3.4 构建树里的 TestXSLT(诊断版补充)
TestXSLT 的 -h(实测全文节选)暴露了它比 Xalan 多出的能力:
TestXSLT options:
Options are case-sensitive.
[-? Shows this message.] [-h Shows this message.]
[-in <source URL> (If not specified, stdin is used.)]
[-xsl <stylesheet URL>] [-out <output file>]
[-v Show version information only.]
[-qc Quiet pattern conflicts warnings.]
[-q Use quiet mode.]
[-indent n Controls how many spaces to indent. (default is 0)]
[-validate Controls whether validation occurs...]
[-tt Trace the templates as they are being called.]
[-tg Trace each generation event.]
[-ts Trace each selection event.]
[-ttc Trace the template children as they are being processed.]
[-xml Use XML formatter.] [-text Use Text formatter.] [-html Use HTML formatter.]
[-dom Use DOM formatter...] [-xst Use source tree formatter...]
[-param name expression Sets a stylesheet parameter.]
[-xd Use Xerces DOM instead of Xalan source tree.]
[-de Disable built-in extension functions.]
[-noindent Turns off HTML indenting.] [-nh Don't generate the XML declaration.]
实测 -in/-xsl/-out 组合转换成功(exit=0)。TestXSLT 的 -v 是"只显示版本"(输出 Xalan version 1.12.0 / Xerces version 3.2.3 后退出),与 Xalan 的 -v(校验开关)同名不同义,混用时务必分清操作的是哪个二进制。
四、TestXPath:XPath 自测工具
4.1 运行方式
构建树产物,不接收参数,运行即执行内置表达式自测:
/root/xalan-c-1.12-build/src/xalanc/TestXPath/TestXPath
实测输出(节选):
Execution of XPath 9 + 7 - 6 * 42 + 36 div 3 + 100 - 2 * 6 succeeded.
The result was -136
Execution of XPath 9 + 7 - 6 + 3 + 24 - 32 - 89 + 123 - 12256 + 89957 succeeded.
The result was 77740
Execution of XPath 0 + 0 succeeded.
The result was 0
Execution of XPath 1 div 2 succeeded.
The result was 0.5
Execution of XPath 1 * 0.25 succeeded.
The result was 0.25
Execution of XPath 3 * 3 * 3 succeeded.
The result was 27
定位是"跑一遍 XPath 求值器自检",不是通用求值器——想对任意表达式求值,走 SimpleXPathAPI 样例或写十几行 XObjectFactory 代码(TestXPath.cpp 源码演示了完整用法:#include <xalanc/XPath/XObjectFactoryDefault.hpp> 等,实测源码 1300+ 行)。
五、MsgCreator:构建期消息编译器
构建树 src/xalanc/Utils/MsgCreator/MsgCreator(实测产物存在)。它不面向用户:构建 Xalan 时先编译 MsgCreator,由它扫描源码消息 ID 生成 XalanMsgLib(libxalanMsg)的源码。安装版不携带、日常零交互。只有在自行新增本地化 locale(重编 NLS 消息目录)时才会接触它。
六、Conf 与 Performance:回归与性能工具
两者都构建于 Tests/ 目录,需要外部的 xalan-test 测试数据(官方 XSLT 测试集,源码包不附带)。裸跑实测:
$ Conf
Using Xalan version 1.12.0
Using Xerces version 3.2.3
conf dir [-sub -out -gold -source (XST | XPL | DOM)]
dir (base directory for testcases)
-sub dir (specific directory)
-out dir (base directory for output)
-gold dir (base directory for gold files)
-source type (parsed source; XalanSourceTree(d), XercesParserLiasion, XercesDOM)
exit=0
指向不存在目录时的行为:
Given base directory "tests/" does not exist
Performance 裸跑打印用法:
Usage: perf [options] -test [test directory ] -result [result directory ] -baseline [baseline directory] -report [report directory ] configfile
结论:没有 xalan-test 数据集时这两件工具只是"会说话的空壳";日常功能验证用 ctest(下节)已足够。
七、16 个官方样例运行实录
7.1 样例清单与运行要求
构建树 samples/ 下 16 个可执行(清单实测),必须在各自信源目录里运行(工作目录需要配套 foo.xml/birds.xsl 等数据文件)。ctest 已自动化这一过程(21 项含 4 项 TraceListen、2 项 SimpleXPathAPI)。
7.2 代表性运行输出(全部实测转录)
XalanTransform(最小变换,结果到标准输出):
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>s1 foo</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<table width="100%" border="0" cellspacing="0" cellpadding="4">
<tr>
<td bgcolor="#006699"><font color="#ffffff" size="+1"><b>Foo</b></font></td>
</tr>
</table>
<p>Hello</p>
<br>
</body>
</html>
UseStylesheetParam(三类参数注入,命令含 4 个参数对):
$ UseStylesheetParam foo.xml foo.xslt foo.out \
-s stringA "'This is a test string value'" \
-n numberA 123.012345 \
-d parmA parmA.xml -d parmB parmB.xml
--- foo.out ---
<?xml version="1.0" encoding="UTF-8"?><OUTPUT><NumberParam>123.012345</NumberParam><root>
<Item>Item-1</Item>
<Item>Item-2</Item>
<Item>Item-3</Item>
</root><ParameterA><xparm>
<Item>First A Item</Item>
<Item>Second A Item</Item>
</xparm></ParameterA><ParameterB><xparm>
<Item>First B Item</Item>
<Item>Second B Item</Item>
</xparm></ParameterB><StringA>This is a test string value</StringA></OUTPUT>
-s/-n/-d 分别对应字符串(带 XPath 引号)、数值、XML 文档节点集三种参数类型,与 API 的三个 setStylesheetParam 重载一一对应。
TraceListen(四种跟踪模式,birds 数据集):
-tt(模板调用)节选:
line 18446744073709551615, column 18446744073709551615.: xsl:template match='/'
line 5, column 29.: xsl:template match='Class'
line 11, column 29.: xsl:template match='Order'
line 27, column 31.: xsl:template match='Species'
(18446744073709551615 即 2^64-1,未关联行号的内置规则显示为最大值,正常现象。)-tg(生成事件)节选:
STARTDOCUMENT
STARTELEMENT: BirdInfo
CHARACTERS:
Order is:
CHARACTERS: TINAMIFORMES
-ts(选择事件)与 -ttc(模板子节点)同样有独立输出格式;-ttc 能看到每个 xsl:value-of/xsl:apply-templates 的行列号,排查"哪条规则输出了什么"时最有用。
SerializeNodeSet(XPath 节点集序列化):
$ SerializeNodeSet foo.xml /doc "name[@first='David']"
<name last="Marston" first="David">Mr. Marston</name><name last="Bertoni" first="David">Mr. Bertoni</name>exit=0
SimpleXPathAPI(两组测试):
The string value of the result is:
Marston (-1 组:/foo:doc foo:name/@last)
The string value of the result is:
Emily (-2 组:/ //foo:name[position()="4"]/@first)
ThreadSafe(三线程并发):
Clock before starting threads: 7006
Starting Thread: 124158280840768
Starting Thread: 124158272448064
Starting Thread: 124158128158272
exit=0
SimpleXPathCAPI(纯 C 接入):
The result of the expression was 'true'.
exit=0
StreamTransform / SimpleTransform / CompileStylesheet / DocumentBuilder / EntityResolver / ExternalFunction / ParsedSourceWrappers / TransformToXercesDOM / XalanTransformerCallback:实测全部 exit=0 正常完成(TransformToXercesDOM 输出 Xerces DOM 序列化树;CompileStylesheet 演示一份样式表对 foo1-foo10 十份 XML 的复用变换)。
八、ctest:一键全量自检
cd /root/xalan-c-1.12-build && ctest
实测结论:21/21 通过,0 失败,总耗时 0.26 秒。升级 Xerces 版本、改编译器或换发行版后,先跑 ctest 再上业务,是最便宜的健康检查。
九、注意事项与常见问题
Q1:Xalan 提示 usage 且 exit=255? 选项拼错或用了 TestXSLT 专属选项(-in/-xsl/-out 等)。Xalan 只认 3.1 节列表里的 10 个短选项。
Q2:-p 传字符串报 XPath error?
给字面量加 XPath 引号:-p title "'Q1 Score'"。裸文本是非法 XPath 表达式。
Q3:exit=254 但看不出哪错?
看 stderr 的 SAXParseException 行,带实体文件名与行列号(实测 at line 1, column 9 精确定位到坏标签)。
Q4:TestXPath 能当表达式计算器吗? 不能,它跑内置自测集。任意表达式求值用 SimpleXPathAPI 思路自写或借 XalanCLI -p + 丢弃输出干跑。
Q5:Conf/Performance 报 base directory does not exist? 缺外部 xalan-test 测试集,需要单独下载并按 -dir 指向它。
Q6:样例二进制在哪、怎么跑? /root/xalan-c-1.12-build/samples/<名>/<名>,必须 cd 到对应源码目录再执行(数据文件在工作目录)。
十、参考链接
- Xalan-C++ 官方主页:https://xalan.apache.org/xalan-c/
- 样例源码仓库:https://github.com/apache/xalan-c
- xalan-test 测试集(Conf/Performance 依赖):https://github.com/apache/xalan-test
- W3C XSLT 1.0 规范:https://www.w3.org/TR/1999/REC-xslt-19991116
- 本专栏相关文档:《Apache Xalan-C++ 在 Ubuntu 22.04 集成使用指南》《Apache Xalan-C++ 1.12 配置参数详解》《Apache Xalan-C++ 介绍与选型指南》