Apache Xalan 常用 CLI 命令与工具详解
沉淀 Xalan-J 2.7.3 命令行工具:Process 帮助全文、XSLTC Compile/Transform、XML+XSL 转 HTML/TEXT 实测、-PARAM 传参、版本查询与 Maven 构建,全部附真实回显。
Apache Xalan 常用 CLI 命令与工具详解
目标:把 Apache Xalan-J 2.7.3 的命令行工具一次讲全——
org.apache.xalan.xslt.Process、org.apache.xalan.xsltc.cmdline.Compile/Transform、org.apache.xalan.Version与 Maven 构建命令。所有命令与回显均在 Ubuntu 22.04.5(OpenJDK 17.0.20.1)与 CentOS 8.5.2111(OpenJDK 17.0.1)实测通过,逐条照抄可复现。
一、命令总览
| 命令 | 归属 jar | 用途 |
|---|---|---|
org.apache.xalan.xslt.Process | xalan.jar | XSLT 一次性转换(解释型或 -XSLTC 编译型) |
org.apache.xalan.xsltc.cmdline.Compile | xalan.jar | 把样式表预编译为 translet 字节码 |
org.apache.xalan.xsltc.cmdline.Transform | xalan.jar | 用编译好的 translet 执行转换 |
org.apache.xalan.Version | xalan.jar | 打印 Xalan-J 版本 |
mvn | Maven | 工程构建、依赖管理 |
以上命令都是 java -cp 直跑的工具类,无守护进程。
二、执行前准备
2.1 定位 jar 并设置 classpath
Maven 工程构建后,两个核心 jar 位于本地仓库:
export CP=/root/.m2/repository/xalan/xalan/2.7.3/xalan-2.7.3.jar:/root/.m2/repository/xalan/serializer/2.7.3/serializer-2.7.3.jar
⚠️ 实测:classpath 缺 serializer.jar 时任何转换都报
XSLT Error (java.lang.NoClassDefFoundError): org/apache/xml/serializer/SerializerTrace。
2.2 版本查询
java -cp $CP org.apache.xalan.Version
✅ 实测回显:
Xalan Java 2.7.3
Process 也支持未写进帮助的 -V 开关:
java -cp $CP org.apache.xalan.xslt.Process -V
✅ 实测回显(首行):
>>>>>> Xalan Version Xalan Java 2.7.3, <<<<<<<
三、Process 帮助文本(全文沉淀)
无参数运行 java -cp $CP org.apache.xalan.xslt.Process 输出两页帮助(第一页末尾 (press <return> to continue) 处需按回车继续)。全文如下:
Xalan-J command line Process class options: -Common Options- [-XSLTC (use XSLTC for transformation)] [-IN inputXMLURL] [-XSL XSLTransformationURL] [-OUT outputFileName] [-E (Do not expand entity refs)] [-EDUMP {optional filename} (Do stackdump on error.)] [-XML (Use XML formatter and add XML header.)] [-TEXT (Use simple Text formatter.)] [-HTML (Use HTML formatter.)] [-PARAM name expression (Set a stylesheet parameter)] [-MEDIA mediaType (use media attribute to find stylesheet associated with a document.)] [-FLAVOR flavorName (Explicitly use s2s=SAX or d2d=DOM to do transform.)] [-DIAG (Print overall milliseconds transform took.)] [-URIRESOLVER full class name (URIResolver to be used to resolve URIs)] [-ENTITYRESOLVER full class name (EntityResolver to be used to resolve entities)] (press <return> to continue) [-CONTENTHANDLER full class name (ContentHandler to be used to serialize output)] [-SECURE (set the secure processing feature to true.)] -Options for Xalan- [-QC (Quiet Pattern Conflicts Warnings)] [-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.)] [-TCLASS (TraceListener class for trace extensions.)] [-L use line numbers for source document] [-INCREMENTAL (request incremental DTM construction by setting http://xml.apache.org/xalan/features/incremental true.)] [-NOOPTIMIMIZE (request no stylesheet optimization processing by setting http://xml.apache.org/xalan/features/optimize false.)] [-RL recursionlimit (assert numeric limit on stylesheet recursion depth.)] -Options for XSLTC- [-XO [transletName] (assign the name to the generated translet)] (press <return> to continue) [-XD destinationDirectory (specify a destination directory for translet)] [-XJ jarfile (packages translet classes into a jar file of name <jarfile>)] [-XP package (specifies a package name prefix for all generated translet classes)] [-XN (enables template inlining)] [-XX (turns on additional debugging message output)] [-XT (use translet to transform if possible)]
参数语义逐项解读见《Apache Xalan 配置参数详解》。
四、Process 转换命令实测
以下示例输入为 data/books.xml(4 条图书记录)与 data/books.xsl(含变量、for-each 循环、choose 条件、format-number 排版、顶层参数 keyword),完整文件见《Apache Xalan 快速入门与集成示例》第三节。
4.1 XML+XSL 转 HTML
cd /opt/xalan-demo && mkdir -p out
java -cp $CP org.apache.xalan.xslt.Process -IN data/books.xml -XSL data/books.xsl -OUT out/cli.html
head -16 out/cli.html
✅ 实测回显:
<html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>图书清单</title> </head> <body> <h1>图书清单(关键字:编程)</h1> <p>共 1 本匹配, 全部图书总价:396.40 元</p> <table cellpadding="4" border="1"> <tr> <th>书名</th><th>作者</th><th>分类</th><th>价格</th> </tr> <tr> <td>Java 并发编程</td><td>王五</td><td><b>编程类</b></td><td align="right">89.90</td> </tr>
4.2 XML+XSL 转 TEXT
样式表声明 <xsl:output method="text"/>,命令行加 -TEXT:
java -cp $CP org.apache.xalan.xslt.Process -IN data/books.xml -XSL data/books-text.xsl -TEXT -OUT out/cli.txt
cat out/cli.txt
✅ 实测回显:
Java 核心技术 | 张三 | 99.50 MySQL 调优实战 | 李四 | 79.00 Java 并发编程 | 王五 | 89.90 TCP/IP 详解 | 赵六 | 128.00
4.3 -PARAM 传参 + -DIAG 计时
java -cp $CP org.apache.xalan.xslt.Process -IN data/books.xml -XSL data/books.xsl -PARAM keyword Java -OUT out/cli-java.html -DIAG
grep -o "<h1>.*</h1>" out/cli-java.html
grep -o "共 [0-9]* 本匹配" out/cli-java.html
✅ 实测回显(Ubuntu 22.04,耗时随机器不同):
--------- Transform of data/books.xml via data/books.xsl took 203 ms <h1>图书清单(关键字:Java)</h1> 共 2 本匹配
⚠️ 实测:POSIX 缺省 locale 下传中文参数(如
-PARAM keyword 数据库)会乱码并导致匹配数为 0,先export LANG=C.UTF-8。
4.4 指定执行模型与输出器
# DOM2DOM 执行模型
java -cp $CP org.apache.xalan.xslt.Process -IN data/books.xml -XSL data/books.xsl -FLAVOR d2d -OUT out/cli-d2d.html
# 强制 XML 输出器(补 XML 声明)
java -cp $CP org.apache.xalan.xslt.Process -IN data/books.xml -XSL data/books.xsl -XML -OUT out/cli-xml.xml
head -4 out/cli-xml.xml
# 不展开实体引用
java -cp $CP org.apache.xalan.xslt.Process -IN data/books.xml -XSL data/books.xsl -E -OUT out/cli-e.html
✅ 实测回显(cli-xml.xml 头部):
<?xml version="1.0" encoding="UTF-8"?><html> <head> <title>图书清单</title> </head>
4.5 XSLTC 编译型引擎一次转换
java -cp $CP org.apache.xalan.xslt.Process -XSLTC -IN data/books.xml -XSL data/books.xsl -OUT out/cli-xsltc.html
head -7 out/cli-xsltc.html
✅ 实测回显(与解释型输出一致):
<html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>图书清单</title> </head> <body> <h1>图书清单(关键字:编程)</h1>
4.6 出错场景与 -EDUMP
构造不合法样式表(未闭合的 xsl:if)后执行:
java -cp $CP org.apache.xalan.xslt.Process -IN data/books.xml -XSL data/books-bad.xsl -OUT out/bad.html -EDUMP out/bad.dmp
ls -l out/bad.dmp
✅ 实测回显(stderr 头部):
[Fatal Error] books-bad.xsl:6:5: The element type "xsl:if" must be terminated by the matching end-tag "</xsl:if>". file:///opt/xalan-demo/data/books-bad.xsl; Line #6; Column #5; org.xml.sax.SAXParseException; systemId: file:///opt/xalan-demo/data/books-bad.xsl; lineNumber: 6; columnNumber: 5; The element type "xsl:if" must be terminated by the matching end-tag "</xsl:if>".
⚠️ 实测:随后还会抛
RuntimeException: Cannot invoke "org.apache.xalan.templates.OutputProperties.getProperties()" because "format" is null——这是错误收尾路径的二次异常;定位样式表问题以第一条 SAXParseException 为准,-EDUMP文件记录的是该二次异常堆栈。
五、XSLTC 独立编译与运行
5.1 Compile 帮助全文
java -cp $CP org.apache.xalan.xsltc.cmdline.Compile
✅ 实测回显(全文):
XSLTC version 1.4 SYNOPSIS java org.apache.xalan.xsltc.cmdline.Compile [-o <output>] [-d <directory>] [-j <jarfile>] [-p <package>] [-n] [-x] [-u] [-v] [-h] { <stylesheet> | -i } OPTIONS -o <output> assigns the name <output> to the generated translet. By default the translet name is derived from the <stylesheet> name. This option is ignored if compiling multiple stylesheets. -d <directory> specifies a destination directory for translet -j <jarfile> packages translet classes into a jar file of the name specified as <jarfile> -p <package> specifies a package name prefix for all generated translet classes. -n enables template inlining (default behavior better on average). -x turns on additional debugging message output -u interprets <stylesheet> arguments as URLs -i forces compiler to read stylesheet from stdin -v prints the version of the compiler -h prints this usage statement
5.2 编译 translet
java -cp $CP org.apache.xalan.xsltc.cmdline.Compile -o BooksTranslet -d out/translet data/books.xsl
ls out/translet/
✅ 实测回显:
BooksTranslet$0.class BooksTranslet$1.class BooksTranslet$2.class BooksTranslet.class
5.3 运行 translet 转换
java -cp "out/translet:$CP" org.apache.xalan.xsltc.cmdline.Transform data/books.xml BooksTranslet > out/translet-run.html
head -3 out/translet-run.html
✅ 实测回显:
<html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
⚠️ 实测两个坑:(1) 该命令生效的参数顺序是 XML 文档在前、translet 类名在后——按传统顺序
Transform BooksTranslet data/books.xml执行会报Translet errors:Cannot find class 'data/books.xml'.;(2) 转换失败时退出码仍为 0,脚本判断须检查输出。
六、java -jar 直跑 Process
xalan-2.7.3.jar 的 MANIFEST 含 Main-Class: org.apache.xalan.xslt.Process 与 Class-Path: xercesImpl.jar xml-apis.jar serializer.jar,可直接 java -jar:
mkdir -p lib
cp /root/.m2/repository/xalan/xalan/2.7.3/xalan-2.7.3.jar lib/
cp /root/.m2/repository/xalan/serializer/2.7.3/serializer-2.7.3.jar lib/serializer.jar
java -jar lib/xalan-2.7.3.jar -IN data/books.xml -XSL data/books.xsl -OUT out/jar.html
head -3 out/jar.html
✅ 实测回显:
<html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
⚠️ 实测:MANIFEST 的
Class-Path按精确文件名找依赖,目录里放serializer-2.7.3.jar无效(报NoClassDefFoundError: org/apache/xml/serializer/SerializerTrace),必须命名为serializer.jar与 xalan.jar 同目录。
七、Maven 构建命令
cd /opt/xalan-demo
mvn -B clean package # 编译打包
mvn -B dependency:tree # 查看依赖树
✅ 实测回显(dependency:tree 关键行):
[INFO] com.example:xalan-demo:jar:1.0.0 [INFO] +- xalan:xalan:jar:2.7.3:compile [INFO] \- xalan:serializer:jar:2.7.3:compile [INFO] BUILD SUCCESS
💡 实测结论:xalan:xalan:2.7.3 的 pom 极简(384 字节),不会传递引入 serializer,两个依赖必须都显式声明。
控制构建 JVM 堆(XSLTC 编译大样式表场景建议 256~512MB):
MAVEN_OPTS="-Xms256m -Xmx512m" mvn -B clean package
实测验证(构建进程存活期间抓取):
ps -ef | grep [j]ava
✅ 实测回显(Ubuntu 22.04,截取关键段):
java -Xms256m -Xmx512m -classpath /usr/share/maven/boot/plexus-classworlds-2.x.jar -Dclassworlds.conf=/usr/share/maven/bin/m2.conf -Dmaven.home=/usr/share/maven -Dlibrary.jansi.path=/usr/share/maven/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/opt/xalan-demo org.codehaus.plexus.classworlds.launcher.Launcher -B clean package
✅ 实测回显(CentOS 8,截取关键段):
java -Xms256m -Xmx512m -classpath /usr/share/java/plexus-classworlds.jar -Dclassworlds.conf=/usr/share/maven/bin/m2.conf -Dmaven.home=/usr/share/maven -Dlibrary.jansi.path=/usr/share/maven/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/opt/xalan-demo
八、JVM 堆与性能验证命令
命令行工具进程直接带堆参数(不读取 MAVEN_OPTS/JAVA_OPTS):
java -Xms256m -Xmx512m -cp $CP org.apache.xalan.xslt.Process -XSLTC -IN data/big.xml -XSL data/books.xsl -OUT out/big.html
进程存活期间用 jps -v 验证(配合一个转换后休眠 20 秒的验证程序 MemoryDemo,源码见《Apache Xalan 快速入门与集成示例》第七节):
jps -v
✅ 实测回显(Ubuntu 22.04):
6757 MemoryDemo -Xms256m -Xmx512m
✅ 实测回显(CentOS 8):
1149 MemoryDemo -Xms256m -Xmx512m
程序内核验 Runtime.getRuntime().maxMemory() 实测输出 JVM 最大堆(maxMemory): 512 MB;-DIAG 输出的毫秒数可用于转换耗时基线对比。
九、常见问题
Q1: Process 无参数运行卡住不动?
答:帮助输出分页,第一页末尾 (press <return> to continue) 在等回车。脚本中采集全文用 printf '\n\n' | java -cp $CP org.apache.xalan.xslt.Process。
Q2: 命令行带中文参数乱码?
答:export LANG=C.UTF-8 后重跑;涉及文件名/参数含中文的脚本都建议在开头固化该设置。
Q3: java -jar lib/xalan-2.7.3.jar 报 NoClassDefFoundError: org/apache/xml/serializer/SerializerTrace?
答:MANIFEST Class-Path 找不到同名依赖。把 serializer 的 jar 改名为 serializer.jar 放到 xalan.jar 同目录(实测验证通过)。
Q4: XSLTC 编译出的 translet 能跨机器分发吗?
答:能。translet 是标准字节码,用 -j out.jar 打包后拷贝到目标机器,java -cp "out.jar:<xalan/serializer jar>" org.apache.xalan.xsltc.cmdline.Transform <xml> <translet类名> 即可运行;目标机也需有 xalan+serializer 运行时。
Q5: 转换大文件时进程被 OOM 杀掉?
答:给该 java 进程加 -Xms256m -Xmx512m(按数据量调大),并用 jps -v 确认参数确实生效(实测命令见第八节)。
Q6: 如何只查版本不执行转换?
答:java -cp $CP org.apache.xalan.Version(干净输出)或 java -cp $CP org.apache.xalan.xslt.Process -V(带装饰输出)。
十、参考链接
- Apache Xalan 官网:https://xalan.apache.org/
- Xalan-J 文档主页:https://xalan.apache.org/xalan-j/
- Xalan-J 命令行工具文档:https://xalan.apache.org/xalan-j/commandline.html
- Maven Central:xalan:xalan:2.7.3:https://central.sonatype.com/artifact/xalan/xalan/2.7.3
- Maven Central 仓库目录:https://repo1.maven.org/maven2/xalan/xalan/
- GitHub 源码仓库(apache/xalan-java):https://github.com/apache/xalan-java