Apache Xerces-J 2.12.2 常用 CLI 命令与工具详解
实测 Apache Xerces-J 2.12.2 官方发行包中的命令行工具,逐个演示 dom.Counter、sax.Counter、sax.Writer、jaxp.SourceValidator 等的用法参数与真实回显,并澄清旧文档中不存在的工具名。
Apache Xerces-J 2.12.2 常用 CLI 命令与工具详解
目标:把 Apache Xerces-J 2.12.2 官方发行包自带的命令行示例工具(xercesSamples.jar)逐个跑通,给出真实用法、参数表与回显,用于不写代码快速校验 XML、统计元素、跟踪解析事件。全部命令与输出均在 Ubuntu 22.04 + OpenJDK 17 环境实测取得。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- JDK:OpenJDK 17.0.20.1
- Xerces-J 官方发行包:Xerces-J-bin.2.12.2.tar.gz(5648672 字节,sha256 为 1ad48949b2c7f0df91668f058d6ec773871adb5527b0b5c73dc2160ab5d162e2)
- 解压目录:/root/xerces-lab/dist/xerces-2_12_2
- 工具运行 classpath 统一为:
xercesSamples.jar:xercesImpl.jar:xml-apis.jar(在解压目录内)
二、工具概览
Xerces-J 没有单一的主命令(没有 xerces 这样的可执行入口),官方工具全部打包在 xercesSamples.jar 中,用 java -cp 按类名调用。先看 jar 里实际有哪些工具类:
cd /root/xerces-lab/dist/xerces-2_12_2
jar tf xercesSamples.jar | grep "\.class$" | sed "s/\.class$//" | sort -u | head -20
实测回显(前 20 行,完整列表还包含 sax/、jaxp/、xni/、xs/、socket/、ui/ 等包):
dom/Counter
dom/DOM3
dom/DOMAddLines
dom/DOMGenerate
dom/ElementPrinter
dom/GetElementsByTagName
dom/ParserWrapper
dom/ParserWrapper$DocumentInfo
dom/Writer
dom/traversal/IteratorView
dom/traversal/IteratorView$1
dom/traversal/IteratorView$2
dom/traversal/IteratorView$3
dom/traversal/IteratorView$4
dom/traversal/IteratorView$Errors
dom/traversal/NameNodeFilter
dom/traversal/TreeWalkerView
dom/traversal/TreeWalkerView$1
dom/traversal/TreeWalkerView$2
dom/traversal/TreeWalkerView$3
⚠️ 注意:网上旧教程常写
sax.SAXCount、sax.SAX2Count、jaxp.Parser——这些类在 2.12.2 的 jar 里不存在(实测 jar tf 无任何 SAXCount/Parser 类)。2.12.2 的计数工具是dom.Counter与sax.Counter。凡与本文类名冲突的旧资料,以 jar tf 实测为准。
| 工具类 | 处理模型 | 用途 |
|---|---|---|
| dom.Counter | DOM | 解析并统计元素/属性/字符数,可开校验 |
| sax.Counter | SAX | 流式解析统计,同上但内存占用小 |
| sax.Writer | SAX | 用 SAX 事件流重建并输出 XML |
| dom.Writer | DOM | 从 DOM 树序列化输出 XML |
| dom.GetElementsByTagName | DOM | 按标签名过滤打印元素结构 |
| sax.DocumentTracer | SAX | 打印全部 SAX 回调事件 |
| xni.DocumentTracer | XNI | 打印解析器底层 XNI 事件 |
| jaxp.SourceValidator | JAXP | 独立 Schema 校验器,支持多种输入源 |
| xs.QueryXS | XS 模型 | 解析 Schema 文件并列出其组件信息 |
💡 技术拓展:同为"计数",dom.Counter 与 sax.Counter 的差别在于底层模型——
模型 内存 速度 可否开校验 DOM(dom.Counter) 与文档大小成正比 较慢(要先建树) 可 SAX(sax.Counter) 常数级 较快(边读边数) 可 验证大文件是否良构/合法优先用 sax.Counter;需要顺带统计层级结构信息时用 dom.Counter。本文两个都实测。
三、前置条件
3.1 下载官方发行包
mkdir -p /root/xerces-lab/dist && cd /root/xerces-lab/dist
curl -sS -L -O https://dlcdn.apache.org/xerces/j/binaries/Xerces-J-bin.2.12.2.tar.gz
sha256sum Xerces-J-bin.2.12.2.tar.gz
实测回显:
1ad48949b2c7f0df91668f058d6ec773871adb5527b0b5c73dc2160ab5d162e2 Xerces-J-bin.2.12.2.tar.gz
3.2 解压并确认目录结构
tar -xzf Xerces-J-bin.2.12.2.tar.gz
ls -la xerces-2_12_2/ | head -16
实测回显(前 16 行,许可系列文件较多,核心 jar 与目录见下):
total 2268
drwxr-xr-x 5 root root 4096 Jan 21 2022 .
drwxr-xr-x 3 root root 4096 Oct 16 00:38 ..
-rw-r--r-- 1 root root 11560 Jan 21 2022 LICENSE
-rw-r--r-- 1 root root 436 Jan 21 2022 LICENSE-SAX.html
-rw-r--r-- 1 root root 5023 Jan 21 2022 LICENSE.DOM-documentation.html
-rw-r--r-- 1 root root 4167 Jan 21 2022 LICENSE.DOM-software.html
-rw-r--r-- 1 root root 11558 Jan 21 2022 LICENSE.resolver.txt
-rw-r--r-- 1 root root 11558 Jan 21 2022 LICENSE.serializer.txt
-rw-r--r-- 1 root root 911 Jan 21 2022 NOTICE
-rw-r--r-- 1 root root 388 Jan 21 2022 NOTICE.resolver.txt
-rw-r--r-- 1 root root 864 Jan 21 2022 NOTICE.serializer.txt
-rw-r--r-- 1 root root 1662 Jan 21 2022 Readme.html
drwxr-xr-x 2 root root 4096 Oct 16 00:39 data
drwxr-xr-x 6 root root 4096 Oct 16 00:38 docs
-rw-r--r-- 1 root root 91981 Jan 21 2022 resolver.jar
(输出节选:列表后半部分还有 samples/ 目录与 serializer.jar、xercesImpl.jar、xercesSamples.jar、xml-apis.jar 四个 jar,解压后大小与 3.1 节 sha256 对应的压缩包内容一致。)
3.3 自带测试数据
data/ 目录自带四份标准测试文件,本文直接使用:
ls xerces-2_12_2/data/
实测回显:
personal-schema.xml
personal.dtd
personal.xml
personal.xsd
四份文件的关系:personal.xml 引用 personal.dtd(DTD 校验用),personal-schema.xml 引用 personal.xsd(Schema 校验用)。
四、各工具详解
4.1 dom.Counter:DOM 解析统计
无参数运行打印用法与默认值:
cd /root/xerces-lab/dist/xerces-2_12_2
CP=xercesSamples.jar:xercesImpl.jar:xml-apis.jar
java -cp $CP dom.Counter
实测回显(输出节选,options 段在前):
usage: java dom.Counter (options) uri ...
options:
-p name Select parser by name.
-x number Select number of repetitions.
-n | -N Turn on/off namespace processing.
-v | -V Turn on/off validation.
-s | -S Turn on/off Schema validation support.
NOTE: Not supported by all parsers.
-f | -F Turn on/off Schema full checking.
NOTE: Requires use of -s and not supported by all parsers.
-hs | -HS Turn on/off honouring of all schema locations.
NOTE: Requires use of -s and not supported by all parsers.
-va | -VA Turn on/off validation of schema annotations.
NOTE: Requires use of -s and not supported by all parsers.
-dv | -DV Turn on/off dynamic validation.
NOTE: Not supported by all parsers.
-xi | -XI Turn on/off XInclude processing.
NOTE: Not supported by all parsers.
-h This help screen.
defaults:
Parser: dom.wrappers.Xerces
Repetition: 1
Namespaces: on
Validation: off
Schema: off
Schema full checking: off
Dynamic: off
XInclude: off
逐项说明:大写字母表示关闭该开关(小写开启);-v 开 DTD 校验,-s 开 Schema 支持(两者可叠加);-x 是重复解析次数(测性能用);默认 Parser 为 dom.wrappers.Xerces(即把 Xerces DOM 解析器包装给 Counter 使用)。
基本统计(默认不校验):
java -cp $CP dom.Counter data/personal.xml
实测回显:
data/personal.xml: 18;6;0 ms (37 elems, 18 attrs, 140 spaces, 128 chars)
输出格式说明:18;6;0 ms 是解析、建树、校验三段耗时毫秒数;括号内依次是元素 37 个、属性 18 个、可忽略空白 140 个、字符 128 个。
开启 DTD 校验(personal.xml 引用 personal.dtd):
java -cp $CP dom.Counter -v data/personal.xml
实测回显:
data/personal.xml: 10;3;0 ms (37 elems, 18 attrs, 140 spaces, 128 chars)
构造违例文档并校验(把 <email> 改成未声明的 <mail>):
sed "s/<email>chief@foo.com<\/email>/<mail>chief@foo.com<\/mail>/" data/personal.xml > data/personal-bad.xml
java -cp $CP dom.Counter -v data/personal-bad.xml
实测回显:
[Error] personal-bad.xml:7:11: Element type "mail" must be declared.
[Error] personal-bad.xml:9:12: The content of element type "person" must match "(name,email*,url*,link?)".
data/personal-bad.xml: 23;4;0 ms (37 elems, 18 attrs, 140 spaces, 128 chars)
同一违例文档不校验运行(只查良构,静默通过):
java -cp $CP dom.Counter data/personal-bad.xml
实测回显:
data/personal-bad.xml: 9;3;0 ms (37 elems, 18 attrs, 140 spaces, 128 chars)
开启 Schema 校验(personal-schema.xml 引用 personal.xsd):
java -cp $CP dom.Counter -v -s data/personal-schema.xml
java -cp $CP dom.Counter -v -s -f data/personal-schema.xml
实测回显(两条均通过,-f 是 Schema 全检查):
data/personal-schema.xml: 56;3;0 ms (37 elems, 20 attrs, 0 spaces, 268 chars)
data/personal-schema.xml: 56;3;0 ms (37 elems, 20 attrs, 0 spaces, 268 chars)
⚠️ 注意:参数必须分开传。实测把
-v -s合写成-vs会被当作文件名处理,报错如下:error: Parse error occurred - /root/xerces-lab/dist/xerces-2_12_2/-vs (No such file or directory) java.io.FileNotFoundException: /root/xerces-lab/dist/xerces-2_12_2/-vs (No such file or directory)Xerces samples 的参数解析器不合并短开关,写
dom.Counter -v -s 文件而不是-vs 文件。
4.2 sax.Counter:SAX 流式统计
java -cp $CP sax.Counter data/personal.xml
实测回显:
data/personal.xml: 6 ms (37 elems, 18 attrs, 140 spaces, 128 chars)
开校验与命名空间(分隔传参):
java -cp $CP sax.Counter -v -n data/personal.xml
实测回显:
data/personal.xml: 7 ms (37 elems, 18 attrs, 140 spaces, 128 chars)
默认值段(无参数运行,输出节选):
java -cp $CP sax.Counter
实测回显:
defaults:
Parser: org.apache.xerces.parsers.SAXParser
Repetition: 1
Namespaces: on
Prefixes: off
Validation: off
Schema: off
Schema full checking: off
Dynamic: off
XInclude: off
逐项说明:sax.Counter 的默认 Parser 直接是 org.apache.xerces.parsers.SAXParser;与 dom.Counter 的差异是多了 Prefixes(namespace-prefixes 开关,需配合 Namespaces 使用)与 Memory、Tagginess 两个可选统计项(用 -m/-t 开启,输出内存与标签密度估计);usage 的 notes 段官方明确说明其耗时"不应作为解析器性能对比依据"。
4.3 sax.Writer 与 dom.Writer:文档重建输出
sax.Writer 按 SAX 事件流重建文档:
java -cp $CP sax.Writer data/personal.xml
实测回显(前 10 行):
<?xml version="1.0" encoding="UTF-8"?>
<personnel>
<person contr="false" id="Big.Boss">
<name><family>Boss</family> <given>Big</given></name>
<email>chief@foo.com</email>
<link subordinates="one.worker two.worker three.worker four.worker five.worker"></link>
</person>
<person contr="false" id="one.worker">
dom.Writer 从 DOM 树序列化输出:
java -cp $CP dom.Writer data/personal.xml
实测回显(前 8 行):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE personnel SYSTEM 'personal.dtd'>
<personnel>
<person contr="false" id="Big.Boss">
<name><family>Boss</family> <given>Big</given></name>
<email>chief@foo.com</email>
两者差异解读:dom.Writer 保留了 <!DOCTYPE ...> 声明行(DOM 树里存有 DocumentType 节点),sax.Writer 默认不输出 DOCTYPE(需开 lexical-handler 类选项);sax.Writer 把空元素输出为 <link ...></link> 完整形式。两者都是"解析-再序列化"的往返验证工具,适合检查解析器对文档的理解是否与原文一致。
4.4 dom.GetElementsByTagName:按标签名过滤
java -cp $CP dom.GetElementsByTagName data/personal.xml name
实测回显(前 8 行):
<personnel>
<person contr="false" id="Big.Boss">
<name>
<family>
<given>
<email>
<link subordinates="one.worker two.worker three.worker four.worker five.worker">
<person contr="false" id="one.worker">
输出含义:先打印文档层级(每行一个元素,缩进表示层级),匹配 name 的元素以特殊标记突出显示。参数为「文件 标签名」两个位置参数。
4.5 sax.DocumentTracer:SAX 事件跟踪
java -cp $CP sax.DocumentTracer data/personal.xml
实测回显(前 12 行):
setDocumentLocator(locator=org.apache.xerces.parsers.AbstractSAXParser$LocatorProxy@76ccd017)
startDocument()
startDTD(name="personnel",publicId=null,systemId="personal.dtd")
startEntity(name="[dtd]")
elementDecl(name="personnel",contentModel="(person)+")
elementDecl(name="person",contentModel="(name,email*,url*,link?)")
attributeDecl(elementName="person",attributeName="id",type="ID",valueDefault="#REQUIRED",value=null)
attributeDecl(elementName="person",attributeName="note",type="CDATA",valueDefault="#IMPLIED",value=null)
attributeDecl(elementName="person",attributeName="contr",type="(true|false)",valueDefault=null,value="false")
attributeDecl(elementName="person",attributeName="salary",type="CDATA",valueDefault="#IMPLIED",value=null)
elementDecl(name="name",contentModel="((family,given)|(given,family))")
elementDecl(name="family",contentModel="(#PCDATA)")
输出说明:每行一个 SAX 回调,缩进体现事件嵌套。从回显可清楚看到 DTD 内部子集的事件序列(startEntity("[dtd]") → elementDecl/attributeDecl 连发)。排查"解析器到底看到了什么"时此工具最直接。
4.6 xni.DocumentTracer:XNI 底层事件跟踪
java -cp $CP xni.DocumentTracer data/personal.xml
实测回显(前 6 行):
startDocument(locator={publicId=null,literal systemId="data/personal.xml",baseSystemId="file:///root/xerces-lab/dist/xerces-2_12_2/data/personal.xml",expanded systemId="file:///root/xerces-lab/dist/xerces-2_12_2/data/personal.xml",lineNumber=1,columnNumber=1},encoding="UTF-8")
xmlDecl(version="1.0",encoding="UTF-8",standalone=null)
doctypeDecl(rootElement="personnel",publicId=null,systemId="personal.dtd")
startDTD(locator={publicId=null,literal systemId="personal.dtd",baseSystemId="file:///root/xerces-lab/dist/xerces-2_12_2/data/personal.dtd",expanded systemId="file:///root/xerces-lab/dist/xerces-2_12_2/data/personal.dtd",lineNumber=1,columnNumber=1})
startExternalSubset()
textDecl(version=null,encoding="UTF-8")
与 SAX 层的对比:XNI 比 SAX 更底层,能看到的 XML 声明(xmlDecl)、DOCTYPE 细节(doctypeDecl)、外部子集开始(startExternalSubset)等 SAX 标准回调里不直接暴露的事件,是开发自定义解析器配置(XNI 组件级扩展)时的观察窗口。
4.7 jaxp.SourceValidator:独立 Schema 校验器
java -cp $CP jaxp.SourceValidator
实测回显(usage 节选):
usage: java jaxp.SourceValidator (options) ...
options:
-l name Select schema language by name.
-x number Select number of repetitions.
-a uri ... Provide a list of schema documents
-i uri ... Provide a list of instance documents to validate
-vs source Select validation source (sax|dom|stax|stream)
-f | -F Turn on/off Schema full checking.
NOTE: Not supported by all schema factories and validators.
合法文档校验:
java -cp $CP jaxp.SourceValidator -a data/personal.xsd -i data/personal-schema.xml -f
实测回显:
data/personal-schema.xml: 5 ms
违例文档校验(复用 4.1 构造的 personal-bad.xml,其中 mail 元素未在 Schema 声明):
java -cp $CP jaxp.SourceValidator -a data/personal.xsd -i data/personal-bad.xml -f
实测回显:
[Error] personal-bad.xml:7:11: cvc-complex-type.2.4.a: Invalid content was found starting with element 'mail'. One of '{email, url, link}' is expected.
data/personal-bad.xml: 11 ms
逐项说明:-a 指定 Schema 文档(可多个),-i 指定实例文档(可多个,逐个校验),-f 开 Schema 全检查,-vs 选择校验执行源(sax/dom/stax/stream 四种,验证不同 API 路径下校验行为一致性)。输出行"文件名: 耗时 ms"表示通过;违例时报 [Error] 行后仍打印耗时行。
4.8 xs.QueryXS:Schema 组件查询
正确用法是喂 Schema 文件(不是实例文档):
java -cp $CP xs.QueryXS data/personal.xsd
实测回显(前 8 行):
Parsing data/personal.xsd...
*************************************************
* Global element declarations: {namespace} name
*************************************************
{null}link
{null}person
{null}url
{null}given
输出说明:列出 Schema 的全局组件(元素声明),{null} 表示目标命名空间为空(personal.xsd 未声明 targetNamespace)。误喂实例文档时报 s4s-* 系列错误:
java -cp $CP xs.QueryXS data/personal-schema.xml
实测回显(前 3 行):
Parsing data/personal-schema.xml...
[xs-error]: s4s-elt-character: Non-whitespace characters are not allowed in schema elements other than 'xs:appinfo' and 'xs:documentation'. Saw 'Boss'.
[xs-error]: s4s-elt-character: Non-whitespace characters are not allowed in schema elements other than 'xs:appinfo' and 'xs:documentation'. Saw 'Big'.
该报错含义是把普通 XML 实例当 Schema 语法解析,s4s 前缀即 "schema for schemas" 校验错误——遇到它先检查参数是不是喂错了文件类型。
五、注意事项
- 运行目录决定相对路径:工具按相对路径找 XML 文件,请在解压目录(xerces-2_12_2)内运行,或写绝对路径。
- 耗时数字不作性能依据:Counter 系列输出中的毫秒值包含 JIT、类加载等噪声,官方 usage 的 notes 段明确提醒不可据此对比解析器性能;测性能应加
-x多次重复并在同一 JVM 内比较。 - 校验默认关闭:所有工具默认 Validation: off、Schema: off,只查良构性;要校验必须显式加
-v、-s(且分开传参)。 - 编码:文件含非 ASCII 字符时,输出依赖终端编码;环境加 LANG=C.UTF-8 可避免乱码。
六、常见问题
Q1:报 FileNotFoundException 且路径是参数本身(如 -vs)。
参数被当成了文件名:samples 参数解析器不支持合并短开关,-v -s 必须拆开写(实测见 4.1)。
Q2:NoClassDefFoundError: dom/Counter。
classpath 没带全。三件套缺一不可:xercesSamples.jar:xercesImpl.jar:xml-apis.jar(工具类在第一个,解析器实现与标准接口在另两个)。
Q3:sax.SAXCount 找不到。 2.12.2 无此类(实测 jar tf 无 SAXCount),对应工具为 sax.Counter;旧教程类名不适用于本版本。
Q4:xs.QueryXS 报 s4s-elt-character 错误。 输入是 XML 实例文档而非 Schema 文件;改传 .xsd 文件(实测见 4.8)。
七、参考链接
- Xerces-J samples 源码目录:发行包内 samples/(与 xercesSamples.jar 内容对应)
- 官方下载:https://dlcdn.apache.org/xerces/j/binaries/
- Xerces-J 官方页:https://xerces.apache.org/xerces2-j/
- 本文配套篇目:《Apache Xerces-J 在 Ubuntu 22.04 集成使用指南》《Apache Xerces-J 2.12.2 配置参数详解》