Apache Xalan-J 2.7.3 配置参数详解

Apache Xalan-J 2.7.3 配置参数实测详解:TransformerFactory 特性与属性矩阵、XSLTC 工厂属性、输出属性、安全处理、ErrorListener 与 URIResolver 自定义,全部参数以真机回显为准。

Apache XalanApache XalanJavaXMLXSLTLinux系统2026/10/16

Apache Xalan-J 2.7.3 配置参数详解

目标:把 Xalan-J 2.7.3 的可配置面——TransformerFactory 特性(feature)、工厂属性(attribute)、输出属性(output property)、安全处理开关、错误监听器与 URI 解析器——逐项跑一遍,用真实回显说明哪些参数实际有效、哪些名存实亡,并给出一份可直接落地的生产配置模板。

一、环境信息

项值
操作系统Ubuntu 22.04.5 LTS(x86_64)
JDKOpenJDK 17.0.20.1(Ubuntu 发行版)
Xalan-J2.7.3(官方二进制包,sha512 校验通过)
涉及 jarxalan.jar、serializer.jar、xercesImpl.jar、xml-apis.jar
$ java -version 2>&1
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
$ sha512sum /root/xalan-j_2_7_3-bin.tar.gz
18373698936776e9ce5818e9ffbf4efe56c44d52ca094b85fa438a59528c369acb27d07afbc85295bbc44698876887616f65d7bc6364defa08b36561e8b3ddc7  /root/xalan-j_2_7_3-bin.tar.gz

二、前置条件

安装 Xalan-J 并准备实验目录:

$ export LANG=C.UTF-8
$ cd /root
$ curl -L -O --max-time 300 https://archive.apache.org/dist/xalan/xalan-j/binaries/xalan-j_2_7_3-bin.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 12.9M  100 12.9M    0     0  4126k      0  0:00:03  0:00:03 --:--:-- 4126k
$ tar xzf xalan-j_2_7_3-bin.tar.gz
$ mkdir -p /root/xalan-lab && cd /root/xalan-lab

本文实验共用一个探测程序骨架:三个工厂实现(独立 Xalan-J 默认工厂、独立 XSLTC 工厂、JDK 内置工厂)分别执行同一组 getFeature/setAttribute,观察接受与拒绝。类路径统一为:

$ export CP=/root/xalan-j_2_7_3/xalan.jar:/root/xalan-j_2_7_3/serializer.jar:/root/xalan-j_2_7_3/xercesImpl.jar:/root/xalan-j_2_7_3/xml-apis.jar

三、参数查看与修改方式

Xalan-J 的参数挂在三个层面,先明确入口才能准确修改:

  1. 工厂选择(决定整套行为基线):类路径 SPI → 系统属性 -Djavax.xml.transform.TransformerFactory=实现类 → JDK 默认(内置引擎)。实测 SPI 优先于 JDK 默认:
$ java -cp classes HelloXalan            # 类路径无 xalan.jar
TransformerFactory 实现类: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
$ java -cp classes:$CP HelloXalan        # xalan.jar 在类路径
TransformerFactory 实现类: org.apache.xalan.processor.TransformerFactoryImpl
  1. 工厂特性:TransformerFactory.getFeature(uri) 查询支持能力;setFeature(uri, boolean) 切换布尔特性。

  2. 工厂属性:setAttribute(name, value) / getAttribute(name),值为字符串;未知名抛 IllegalArgumentException。

  3. 输出属性:Transformer.setOutputProperty(key, value),标准键定义在 javax.xml.transform.OutputKeys,扩展键用 {命名空间}键名 形式。

命令行工具的等价开关(-SECURE、-INCREMENTAL、-NOOPTIMIMIZE 等)会在对应小节交叉验证。

四、参数总览

4.1 标准 JAXP 特性(getFeature)

对三个工厂执行 getFeature 的真实结果:

特性 URI独立 Xalan-J 默认工厂独立 XSLTC 工厂JDK 内置工厂
http://javax.xml.transform.stream.StreamSource/featuretruetruetrue
http://javax.xml.transform.stream.StreamResult/featuretruetruetrue
http://javax.xml.transform.dom.DOMSource/featuretruetruetrue
http://javax.xml.transform.dom.DOMResult/featuretruetruetrue
http://javax.xml.transform.sax.SAXSource/featuretruetruetrue
http://javax.xml.transform.sax.SAXResult/featuretruetruetrue
http://javax.xml.transform.sax.SAXTransformerFactory/featuretruetruetrue

三个工厂都实现了 SAXTransformerFactory 接口(可创建 TemplatesHandler/ResultHandler),实测 newTemplatesHandler() 返回 org.apache.xalan.processor.StylesheetHandler。

4.2 Xalan-J 自有特性(getFeature 实测回显)

$ java -cp classes:$CP FeatureProbe
===== A. TransformerFactory.newInstance()(classpath 决定) =====
factory = org.apache.xalan.processor.TransformerFactoryImpl
getFeature(http://xml.apache.org/xalan/features/optimize) = false
getFeature(http://xml.apache.org/xalan/features/incremental) = false
getFeature(http://xml.apache.org/xalan/features/source_location) = false
getFeature(http://www.oracle.com/xsl/jaxp/transform/feat/enable-extension-functions) = false
getFeature(http://www.oracle.com/xsl/jaxp/transform/feat/lang) = false

注意:对未知特性 getFeature 一律返回 false 而非报错,不能用它判断参数有效性——要看 setAttribute 的真实反应。

4.3 解释器工厂属性(setAttribute 实测回显,接上)

setAttribute(http://xml.apache.org/xalan/features/optimize, true) 成功
setAttribute(http://xml.apache.org/xalan/features/incremental, true) 成功
setAttribute(http://xml.apache.org/xalan/features/source_location) 拒绝: Not supported: http://xml.apache.org/xalan/features/source_location
setAttribute(http://javax.xml.XMLConstants/property/accessExternalStylesheet) 拒绝: Not supported: http://javax.xml.XMLConstants/property/accessExternalStylesheet
setAttribute(http://javax.xml.XMLConstants/property/accessExternalDTD) 拒绝: Not supported: http://javax.xml.XMLConstants/property/accessExternalDTD
setAttribute(http://www.oracle.com/xsl/jaxp/transform/feat/enable-extension-functions) 拒绝: Not supported: http://www.oracle.com/xsl/jaxp/transform/feat/enable-extension-functions

小结表:

参数实测结论
http://xml.apache.org/xalan/features/optimize接受(性能优化开关)
http://xml.apache.org/xalan/features/incremental接受(增量式解析,交互场景降低首结果延迟)
http://xml.apache.org/xalan/features/source_location名存实亡:getFeature=false,setAttribute 报 Not supported
accessExternalStylesheet / accessExternalDTD(JAXP 安全属性)不支持;Xalan-J 2.7.3 的外部访问限制走 FEATURE_SECURE_PROCESSING
http://www.oracle.com/xsl/jaxp/transform/feat/enable-extension-functions不被识别(JDK 8 时代产物,JDK 17 内置引擎同样不认,实测见下)

4.4 XSLTC 工厂属性(org.apache.xalan.xsltc.trax.TransformerFactoryImpl)

对 10 个属性先查默认值再逐个 setAttribute 的真实回显:

== 1. 各属性默认值(getAttribute,全新工厂实例) ==
getAttribute(translet-name) = GregorSamsa
getAttribute(destination-directory) 拒绝: TransformerFactory does not recognise attribute 'destination-directory'.
getAttribute(package-name) 拒绝: TransformerFactory does not recognise attribute 'package-name'.
getAttribute(jar-name) 拒绝: TransformerFactory does not recognise attribute 'jar-name'.
getAttribute(generate-translet) = false
getAttribute(auto-translet) = false
getAttribute(use-classpath) 拒绝: TransformerFactory does not recognise attribute 'use-classpath'.
getAttribute(debug) 拒绝: TransformerFactory does not recognise attribute 'debug'.
getAttribute(enable-inlining) = false
getAttribute(indent-number) 拒绝: TransformerFactory does not recognise attribute 'indent-number'
== 2. setAttribute 逐个实测(每个属性用独立工厂实例) ==
setAttribute(translet-name,HelloTranslet) 成功, 回读=HelloTranslet
setAttribute(destination-directory) 拒绝: TransformerFactory does not recognise attribute 'destination-directory'.
setAttribute(package-name) 拒绝: TransformerFactory does not recognise attribute 'package-name'.
setAttribute(jar-name) 拒绝: TransformerFactory does not recognise attribute 'jar-name'.
setAttribute(generate-translet,true) 成功, 回读=true
setAttribute(auto-translet,false) 成功, 回读=false
setAttribute(use-classpath) 拒绝: TransformerFactory does not recognise attribute 'use-classpath'.
setAttribute(debug) 拒绝: TransformerFactory does not recognise attribute 'debug'.
setAttribute(enable-inlining,false) 成功, 回读=false
setAttribute(indent-number) 拒绝: TransformerFactory does not recognise attribute 'indent-number'.

💡 技术拓展:GregorSamsa(卡夫卡《变形记》主角)是 XSLTC 生成 translet 的默认类名,属于源码里的彩蛋级默认值。javap -constants 能看到 destination-directory、jar-name 等常量确实存在于该工厂类,但 2.7.3 的 setAttribute 实际只接受 translet-name、generate-translet、auto-translet、enable-inlining 四个——以运行时行为为准。

4.5 JDK 内置工厂对照(--add-exports 放开模块封装后实测)

$ java --add-exports java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED -cp classes FeatureProbe
===== D. com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl(JDK 内置) =====
factory = com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
setAttribute(http://xml.apache.org/xalan/features/optimize) 拒绝: TransformerFactory does not recognise attribute 'http://xml.apache.org/xalan/features/optimize'.
setAttribute(http://xml.apache.org/xalan/features/incremental) 拒绝: TransformerFactory does not recognise attribute 'http://xml.apache.org/xalan/features/incremental'.
setAttribute(http://xml.apache.org/xalan/features/source_location) 拒绝: TransformerFactory does not recognise attribute 'http://xml.apache.org/xalan/features/source_location'.
setAttribute(http://javax.xml.XMLConstants/property/accessExternalStylesheet, file) 成功
setAttribute(http://javax.xml.XMLConstants/property/accessExternalDTD, all) 成功
setAttribute(http://www.oracle.com/xsl/jaxp/transform/feat/enable-extension-functions) 拒绝: TransformerFactory does not recognise attribute 'http://www.oracle.com/xsl/jaxp/transform/feat/enable-extension-functions'.
参数JDK 内置工厂独立 Xalan-J
accessExternalStylesheet / accessExternalDTD成功Not supported
oracle enable-extension-functions不识别(旧 JDK 行为已移除)Not supported

不加 --add-exports 时的原始报错(真实回显):

D. 反射实例化被 JDK 17 模块封装拒绝: java.lang.IllegalAccessException
   原因: module java.xml does not export com.sun.org.apache.xalan.internal.xsltc.trax

五、核心参数分类详解

5.1 解释器引擎特性:optimize 与 incremental

两个被接受的特性与命令行开关一一对应(Process -INCREMENTAL 实测可用;-NOOPTIMIMIZE 实测报 Invalid option,详见《Apache Xalan-J 命令行工具详解》):

$ java -cp $CP org.apache.xalan.xslt.Process -INCREMENTAL -IN hello.xml -XSL hello.xsl
<?xml version="1.0" encoding="UTF-8"?><message>Hello, Xalan-J! Your XSLT engine is Apache Software Foundation.</message>
  • optimize=false:关闭 XPath 优化模式,遇到含非法输入会抛异常的极端样式时排障用。
  • incremental=true:增量式处理(DTM 增量构建),大文档交互式渲染场景可显著降低"首个输出"延迟,总吞吐会下降。

5.2 XSLTC 工厂属性:generate-translet 落盘实测

设置 generate-translet=true 后,newTransformer(xsl) 会在内存编译 translet 的同时把字节码写到磁盘,默认类名 GregorSamsa、指定 translet-name 后为自定义名(实测产物):

$ ls -l HelloTranslet.class
-rw-r--r-- 1 root root 3275 Oct 16 00:51 HelloTranslet.class
  • translet-name:translet 类名(默认 GregorSamsa)。
  • generate-translet=true:变换时把编译产物落盘(默认 false)。
  • auto-translet=true:先尝试从类路径加载既有 translet,找不到再编译(默认 false)。
  • enable-inlining:方法体优化开关,默认 false;true 时编译产物更小、生成更快,但运行稍慢。
  • indent-number:常量存在但 setAttribute 拒绝;序列化缩进实际走输出属性(见 5.3)。

命令行的等价产物:Process -XSLTC -XO processtranslet -XSL hello.xsl 实测生成 processtranslet.class(3277 字节)。

5.3 输出属性(OutputKeys 与扩展键)

标准键逐个 set 的实测(10 个标准键全部成功,非法值 indent=maybe 也未即时报错,校验延迟到序列化期):

$ java -cp classes:$CP OutputPropDemo
factory = org.apache.xalan.processor.TransformerFactoryImpl
set 成功: method = xml
set 成功: version = 1.0
set 成功: encoding = UTF-8
set 成功: omit-xml-declaration = no
set 成功: standalone = yes
set 成功: doctype-public = -//Example//DTD Demo//EN
set 成功: doctype-system = demo.dtd
set 成功: media-type = application/xml
set 成功: cdata-section-elements = name
set 成功: indent = yes
set 成功: indent = maybe
set 成功: {http://xml.apache.org/xalan}indent-amount = 4
set 成功: {http://xml.apache.org/xslt}indent-amount = 4
set 成功: {http://xml.apache.org/xalan}line-separator = 

关键实测:扩展键被接受但缩进值在独立 Xalan-J 上不生效。identity 变换对照(独立 Xalan-J 默认缩进 2 空格;设 4、设 2 均无变化):

$ java -cp classes:$CP IndentDemo
== factory = org.apache.xalan.processor.TransformerFactoryImpl
== (1) 仅 indent=yes(默认缩进) ==
<?xml version="1.0" encoding="UTF-8"?><greeting>
  <name>Xalan-J</name>
</greeting>
== (2) indent=yes + {http://xml.apache.org/xalan}indent-amount=4 ==
<?xml version="1.0" encoding="UTF-8"?><greeting>
  <name>Xalan-J</name>
</greeting>

JDK 内置引擎对照(输出里混有纯空白行,行尾空白已如实保留;设 {http://xml.apache.org/xslt}indent-amount=2 后缩进收窄,实测生效):

== (1) 仅 indent=yes(默认缩进) ==
<?xml version="1.0" encoding="UTF-8"?><greeting>
      
    <name>Xalan-J</name>
    
</greeting>
== (3) indent=yes + {http://xml.apache.org/xslt}indent-amount=2 ==
<?xml version="1.0" encoding="UTF-8"?><greeting>
    
  <name>Xalan-J</name>
  
</greeting>

结论:控制缩进粒度不要依赖 indent-amount 扩展键,输出格式化交给 XSLT 样式表自身排版或后续格式化工具。

5.4 安全处理参数

解释器工厂支持标准 FEATURE_SECURE_PROCESSING 的 setFeature(但同 URI 的 setAttribute 被拒绝——两个入口行为不同,实测):

factory = org.apache.xalan.processor.TransformerFactoryImpl
setFeature(secure-processing, true) 成功
setAttribute 拒绝: Not supported: http://javax.xml.XMLConstants/feature/secure-processing

开启后 Java 扩展立即被禁(命令行 -SECURE 与之等价,实测):

$ java -cp $CP org.apache.xalan.xslt.Process -SECURE -IN employees.xml -XSL exslt-test.xsl
<?xml version="1.0" encoding="UTF-8"?><report>
<java-ext>(Location of error unknown)Extension function: '{http://xml.apache.org/xalan/java/java.lang.Math}sqrt' can not be invoked when the XMLConstants.FEATURE_SECURE_PROCESSING feature is set to true.

注意:错误文本直接混入输出流,命令退出码仍为 0——命令行模式下排障不能只看退出码,还得检查输出内容。

安全基线建议:不可信样式表一律 setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);独立 Xalan-J 不支持 accessExternal* 白名单参数,目录遍历类风险靠文件系统权限与部署形态兜底。

5.5 扩展函数特性 URI 的真伪

http://www.oracle.com/xsl/jaxp/transform/feat/enable-extension-functions 与 .../feat/lang 在本文三个工厂上全部不被识别或返回 false(JDK 8 的旧机制,JDK 17.0.20.1 已移除)。控制扩展函数的真实有效手段就是 5.4 的 secure-processing。

六、ErrorListener 与 URIResolver 自定义

6.1 ErrorListener:默认行为与自定义

样式表引用未定义变量(bad.xsl:<xsl:value-of select="$notdefined"/>)。默认监听器把错误打印到控制台,但 newTemplates 照常"成功",newTransformer 不抛异常而是返回 null,到 transform 才以 NPE 形式炸出(进程退出码 1):

$ java -cp classes:$CP BadRun
file:/root/xalan-lab/bad.xsl; Line #4; Column #41; org.apache.xml.utils.WrappedRuntimeException: Could not find variable with the name of notdefined
newTransformer 通过,继续 transform ...
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "javax.xml.transform.Transformer.transform(javax.xml.transform.Source, javax.xml.transform.Result)" because "<local2>" is null
	at BadRun.main(BadRun.java:11)

自定义 ErrorListener 后,同一错误以 fatalError 回调进入自定义代码(实测)——但监听器只负责接收通知,回调不主动抛异常时流程照常继续:

$ java -cp classes:$CP ErrorListenerDemo custom
factory = org.apache.xalan.processor.TransformerFactoryImpl
已注册自定义 ErrorListener
[致命] org.apache.xml.utils.WrappedRuntimeException: Could not find variable with the name of notdefined
编译通过(未抛出异常)

生产要点:newTransformer/newTemplates 返回值必须判空;自定义 fatalError 中抛出 TransformerException 可把失败显式化。

6.2 URIResolver:xsl:import 的路径重定向

样式表 importer.xsl 引用 <xsl:import href="common.xsl"/>,而 common.xsl 实际在 lib/ 子目录。不设解析器时默认解析失败(IO 异常与"找不到 footer 模板"两轮报错打到控制台后流程照走,最终输出 <page/>,footer 悄悄消失——一个危险的静默降级,实测):

$ java -cp classes:$CP UriResolverDemo
factory = org.apache.xalan.processor.TransformerFactoryImpl
file:/root/xalan-lab/importer.xsl; Line #3; Column #34; Had IO Exception with stylesheet file: common.xsl
file:/root/xalan-lab/importer.xsl; Line #7; Column #41; org.xml.sax.SAXException: javax.xml.transform.TransformerException: ElemTemplateElement error: footer
javax.xml.transform.TransformerException: ElemTemplateElement error: footer
<?xml version="1.0" encoding="UTF-8"?>file:/root/xalan-lab/importer.xsl; Line #7; Column #41; Could not find template named: footer
<page/>

注册 URIResolver 把 href 映射到 lib/ 后恢复(实测,解析回调清晰可见):

$ java -cp classes:$CP UriResolverDemo with-resolver
factory = org.apache.xalan.processor.TransformerFactoryImpl
[URIResolver] href=common.xsl base=file:/root/xalan-lab/importer.xsl
[URIResolver] 命中本地映射: lib/common.xsl
<?xml version="1.0" encoding="UTF-8"?><page>
<footer>rendered-by=Apache Software Foundation</footer>
</page>

命令行等价物:Process -URIRESOLVER MyResolver -IN hello.xml -XSL importer.xsl,实测回调与输出同上(MyResolver 为实现 javax.xml.transform.URIResolver 的类,须在类路径)。

七、生产配置模板

综合以上实测,一份可落地的 Java 侧配置模板:

// 1) 用系统属性或类路径 SPI 固定引擎(不要依赖反射创建内部工厂)
//    java -Djavax.xml.transform.TransformerFactory=org.apache.xalan.processor.TransformerFactoryImpl ...

TransformerFactory factory = TransformerFactory.newInstance();
// 2) 安全基线:不可信样式表必开(实测 setFeature 支持、setAttribute 不支持)
factory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing", true);
// 3) 显式失败:未定义变量等错误走 fatalError 并抛出
factory.setErrorListener(new ErrorListener() {
    public void warning(TransformerException e)   { log.warn(e.getMessageAndLocation()); }
    public void error(TransformerException e)     { throw e; }
    public void fatalError(TransformerException e){ throw e; }
});
// 4) 资源隔离:import/include/document() 一律经 URIResolver 映射到受控目录
factory.setURIResolver((href, base) -> resolveUnderWhitelist(href, base));

// 5) 判空 + Templates 缓存复用
Templates templates = factory.newTemplates(new StreamSource(xslFile));
if (templates == null) throw new IllegalStateException("样式表编译失败");
Transformer transformer = templates.newTransformer();
transformer.setErrorListener(factory.getErrorListener());
transformer.transform(new StreamSource(xmlFile), new StreamResult(outFile));

高吞吐场景追加:factory.setAttribute("http://xml.apache.org/xalan/features/optimize", "false") 仅在排障时使用;常规性能优化走 XSLTC——用 org.apache.xalan.xsltc.trax.TransformerFactoryImpl + generate-translet=true 把编译产物固化,或直接用命令行预编译(见《Apache Xalan-J 命令行工具详解》)。

八、常见问题

  1. indent-amount 设了没效果? 实测独立 Xalan-J 解释器对该扩展键不生效(见 5.3),JDK 内置引擎认 {http://xml.apache.org/xslt}indent-amount。统一输出格式不要指望这个键。
  2. newTransformer 返回 null 而不是抛异常? Xalan-J 解释器对某些编译错误只回调监听器并返回 null(见 6.1 实测),务必判空;自定义 fatalError 抛异常可获得显式失败。
  3. setAttribute 报 "Not supported"/"does not recognise"? 以实测矩阵为准(第四章),不要按 javap 常量或旧教程配置。
  4. 报 module java.xml does not export com.sun...? JDK 17 模块封装,改用 SPI/系统属性选择工厂;调试用 --add-exports(见 4.5)。
  5. 控制台中文变问号? export LANG=C.UTF-8(缺 UTF-8 locale 的系统普遍存在)。
  6. -NOOPTIMIMIZE 报 Invalid option? 该开关在 2.7.3 的 Process 里名存实亡,代码侧用 features/optimize 属性替代。

九、参考链接

  1. 《Apache Xalan-J 介绍与选型指南》——架构与选型背景。
  2. 《Apache Xalan-J 在 Ubuntu 22.04 集成使用指南》——安装、依赖与 API 基础。
  3. 《Apache Xalan-J 命令行工具详解》——本文各参数的命令行等价物实测。
  4. Xalan-J Usage Patterns:https://xalan.apache.org/xalan-j/usagepatterns.html
  5. javax.xml.transform API 文档(JDK 17):https://docs.oracle.com/en/java/javase/17/docs/api/java.xml/javax/xml/transform/package-summary.html