Apache Xerces-J 2.12.2 配置参数详解
逐项实测 Apache Xerces-J 2.12.2 的 JAXP feature/property 参数,覆盖校验、命名空间、Schema、XXE 防护等核心开关的真实行为、默认值与异常对照,并给出生产安全配置模板。
Apache Xerces-J 2.12.2 配置参数详解
目标:把 Apache Xerces-J 2.12.2 通过 setFeature/setProperty 暴露的核心配置参数逐个实测一遍,给出每个参数的真实默认值、行为差异回显与生产推荐组合。全部输出在 Ubuntu 22.04 + OpenJDK 17 + Xerces-J 2.12.2 环境实测取得。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- JDK:OpenJDK 17.0.20.1
- Xerces-J:2.12.2(xercesImpl-2.12.2.jar,sha256 前缀 6fc99182)
- 演示目录:/root/xerces-lab(源码 src/、编译输出 classes/、依赖 libs/)
- 编译命令统一为:
javac -encoding UTF-8 -cp libs/xercesImpl-2.12.2.jar -d classes src/*.java(实测无输出即成功) - 运行 classpath 统一为:
classes:libs/xercesImpl-2.12.2.jar
二、前置条件
本篇所有示例都需要 xercesImpl-2.12.2.jar。手动获取方式(一条命令即可独立完成):
mkdir -p /root/xerces-lab/libs && cd /root/xerces-lab/libs
curl -sS -O https://repo1.maven.org/maven2/xerces/xercesImpl/2.12.2/xercesImpl-2.12.2.jar
sha256sum xercesImpl-2.12.2.jar
实测回显:
6fc991829af1708d15aea50c66f0beadcd2cfeb6968e0b2f55c1b0909883fe16 xercesImpl-2.12.2.jar
示例中直接实例化 Xerces 的 org.apache.xerces.parsers.SAXParser 类,因此 classpath 必须包含该 jar(这正是"参数是否为 Xerces 专有"的判定边界:http://xml.org/sax/features/* 是 SAX 标准参数,http://apache.org/xml/* 是 Xerces 专有参数)。
三、参数查看与修改方式
Xerces 的参数分两类:feature(布尔开关,用 setFeature/getFeature)与 property(对象值,用 setProperty/getProperty)。两者设置失败时分别可能抛 SAXNotRecognizedException(不认识)或 SAXNotSupportedException(认识但当前状态不支持)。写两个探针程序统一实测:
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
public class FeatureProbe {
public static void main(String[] args) {
String uri = args[0];
boolean value = Boolean.parseBoolean(args[1]);
try {
SAXParser parser = new SAXParser();
parser.setFeature(uri, value);
System.out.println("setFeature 成功: " + uri + " = " + value);
System.out.println("getFeature 读回: " + parser.getFeature(uri));
} catch (SAXException e) {
if (e instanceof SAXNotRecognizedException) {
System.out.println("SAXNotRecognizedException(解析器不识别该 feature): " + uri);
} else if (e instanceof SAXNotSupportedException) {
System.out.println("SAXNotSupportedException(当前状态下不允许设置该 feature): " + uri);
} else {
System.out.println("SAXException: " + e.getMessage());
}
}
}
}
PropertyProbe 与 FeatureProbe 结构完全相同,仅两处差异:parser.setFeature(uri, value) 换成 parser.setProperty(uri, value)、parser.getFeature(uri) 换成 parser.getProperty(uri)(完整源码按此替换即可编译,实测编译通过)。
编译并先做异常对照(用一个不存在的参数名):
cd /root/xerces-lab/src
CP=../classes:../libs/xercesImpl-2.12.2.jar
java -cp $CP FeatureProbe http://xml.org/sax/features/bogus-feature true
java -cp $CP PropertyProbe http://apache.org/xml/properties/bogus-prop xyz
实测回显:
SAXNotRecognizedException(解析器不识别该 feature): http://xml.org/sax/features/bogus-feature
SAXNotRecognizedException(解析器不识别该 property): http://apache.org/xml/properties/bogus-prop
验证结论:探针可用。后续每个参数的"set 成功/读回值"都按同样方式取得。
四、参数总览
| 参数 URI | 类型 | 默认值(实测读回) | 作用 |
|---|---|---|---|
| http://xml.org/sax/features/validation | feature | false | DTD 校验总开关 |
| http://xml.org/sax/features/namespaces | feature | true | 命名空间处理 |
| http://xml.org/sax/features/namespace-prefixes | feature | false | 保留原始前缀与 xmlns 属性 |
| http://apache.org/xml/features/validation/schema | feature | false | XML Schema 校验(Xerces 专有) |
| http://apache.org/xml/features/validation/schema-full-checking | feature | false | Schema 严格全检查(Xerces 专有) |
| http://apache.org/xml/features/validation/dynamic | feature | false | 动态校验(有 DTD/Schema 才校验) |
| http://apache.org/xml/features/disallow-doctype-decl | feature | false | 禁止 DOCTYPE(XXE 防护) |
| http://apache.org/xml/features/nonvalidating/load-external-dtd | feature | true | 非校验模式下也加载外部 DTD |
| http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation | property | 无 | 指定无命名空间文档的 Schema |
| http://apache.org/xml/properties/schema/external-schemaLocation | property | 无 | 按"命名空间 URI 位置"指定 Schema |
| http://java.sun.com/xml/jaxp/properties/schemaLanguage | property | 无 | JAXP 标准:Schema 语言标识 |
| http://java.sun.com/xml/jaxp/properties/schemaSource | property | 无 | JAXP 标准:Schema 来源 |
上表 12 个参数均已用探针逐一实测:setFeature/setProperty 全部成功且 getFeature/getProperty 读回值与设置值一致。代表样例回显:
java -cp $CP FeatureProbe http://xml.org/sax/features/validation true
java -cp $CP FeatureProbe http://apache.org/xml/features/nonvalidating/load-external-dtd false
java -cp $CP PropertyProbe http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation books.xsd
实测回显:
setFeature 成功: http://xml.org/sax/features/validation = true
getFeature 读回: true
setFeature 成功: http://apache.org/xml/features/nonvalidating/load-external-dtd = false
getFeature 读回: false
setProperty 成功: http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation = books.xsd
getProperty 读回: books.xsd
每个参数的行为级差异(开关前后解析结果变化)在第五章逐项演示。
💡 技术拓展:XML 校验语言不止一种,Xerces 两个开关对应两类——
校验语言 开关 特点 DTD validation feature 语法级约束、定义在文档内部或外部 DTD 文件 XML Schema 1.0 validation/schema feature + schemaSource property 类型系统强(decimal、date 等),namespace 感知 RELAX NG / Schematron Xerces-J 内置不直接支持 需第三方实现(如 Jing) 本文全部采用 Xerces 内置的 DTD 与 XML Schema 1.0 两条链路实测。
五、核心参数分类详解
5.1 validation:DTD 校验开关
该参数决定是否对文档执行 DTD 校验。默认 false 时只检查良构性。测试数据 note.xml(引用 note.dtd 但缺少 heading 元素)与 note.dtd:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>张三</to>
<from>李四</from>
<body>会议改到下午三点</body>
</note>
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
测试程序:
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class DtdValidateDemo {
public static void main(String[] args) throws Exception {
boolean validate = Boolean.parseBoolean(args[1]);
SAXParser parser = new SAXParser();
parser.setFeature("http://xml.org/sax/features/validation", validate);
final int[] problems = {0};
parser.setErrorHandler(new DefaultHandler() {
@Override
public void error(SAXParseException e) {
problems[0]++;
System.out.println("[错误] 第" + e.getLineNumber() + "行: " + e.getMessage());
}
@Override
public void warning(SAXParseException e) {
System.out.println("[警告] 第" + e.getLineNumber() + "行: " + e.getMessage());
}
@Override
public void fatalError(SAXParseException e) {
problems[0]++;
System.out.println("[致命错误] 第" + e.getLineNumber() + "行: " + e.getMessage());
}
});
try {
parser.parse(args[0]);
} catch (SAXException e) {
System.out.println("解析中止: " + e.getMessage());
}
if (problems[0] > 0) {
System.out.println("结果: 共发现 " + problems[0] + " 处问题。");
} else {
System.out.println("结果: 解析结束,未发现问题。");
}
System.out.println("(本次 validation feature = " + validate + ")");
}
}
开启校验运行:
java -cp $CP DtdValidateDemo note.xml true
实测回显:
[错误] 第7行: The content of element type "note" must match "(to,from,heading,body)".
结果: 共发现 1 处问题。
(本次 validation feature = true)
关闭校验运行:
java -cp $CP DtdValidateDemo note.xml false
实测回显:
结果: 解析结束,未发现问题。
(本次 validation feature = false)
验证结论:同一份违例文档,validation=true 报内容模型错误,false 时静默通过。校验必须显式开启是 Xerces(以及所有 SAX 解析器)最常被忽略的默认行为。
5.2 namespaces / namespace-prefixes:命名空间处理
namespaces=true(默认)时回调的 uri/localName 有值;false 时只保留原始 qName。测试文档 nsbooks.xml(带 store: 前缀):
<?xml version="1.0" encoding="UTF-8"?>
<store:bookstore xmlns:store="http://example.com/store">
<store:book id="2001">
<store:title>XML 实战</store:title>
<store:price>59.00</store:price>
</store:book>
</store:bookstore>
测试程序:
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
public class NamespaceDemo {
public static void main(String[] args) throws Exception {
boolean aware = Boolean.parseBoolean(args[0]);
SAXParser parser = new SAXParser();
parser.setFeature("http://xml.org/sax/features/namespaces", aware);
parser.setContentHandler(new DefaultHandler() {
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) {
System.out.println("开始元素: qName=" + qName + ", localName=" + localName
+ ", uri=" + (uri.isEmpty() ? "(空)" : uri));
}
});
parser.parse(args[1]);
System.out.println("(本次 namespaces feature = " + aware + ")");
}
}
namespaces=true 运行:
java -cp $CP NamespaceDemo true nsbooks.xml
实测回显:
开始元素: qName=store:bookstore, localName=bookstore, uri=http://example.com/store
开始元素: qName=store:book, localName=book, uri=http://example.com/store
开始元素: qName=store:title, localName=title, uri=http://example.com/store
开始元素: qName=store:price, localName=price, uri=http://example.com/store
(本次 namespaces feature = true)
namespaces=false 运行:
java -cp $CP NamespaceDemo false nsbooks.xml
实测回显:
开始元素: qName=store:bookstore, localName=, uri=(空)
开始元素: qName=store:book, localName=, uri=(空)
开始元素: qName=store:title, localName=, uri=(空)
开始元素: qName=store:price, localName=, uri=(空)
(本次 namespaces feature = false)
⚠️ 注意:namespaces=false 时所有元素的 localName 为空串、uri 为空串、qName 保留带前缀的原始名。两个开关叠加使用:namespaces=true + namespace-prefixes=true 时既有 uri/localName 又保留 xmlns 声明属性与前缀。
namespace-prefixes=true 的作用是与 namespaces=true 叠加,让 xmlns 声明也作为属性出现在 Attributes 里、qName 保留前缀(探针实测 setFeature 成功、读回 true,见第四章总览)。
5.3 validation/schema + external-noNamespaceSchemaLocation:Schema 校验
Xerces 专有链路:开 http://apache.org/xml/features/validation/schema,再用 property 指定 Schema 文件。测试程序复用 5.1 的 DtdValidateDemo 整体骨架(ErrorHandler 匿名类与 error 计数完全相同),仅替换参数设置部分,核心片段如下(完整类按骨架拼装即可编译,实测编译通过、输出如下):
SAXParser parser = new SAXParser();
parser.setFeature("http://xml.org/sax/features/validation", true);
parser.setFeature("http://apache.org/xml/features/validation/schema", true);
parser.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
args[1]);
parser.setErrorHandler(handlerWithCounting); // 与 5.1 相同的 ErrorHandler 匿名类
parser.parse(args[0]); // 结果打印逻辑也与 5.1 相同
测试数据 books.xml 与 books.xsd(books.xsd 定义 bookstore/book/title/author/price,price 类型 xs:decimal,id 必填):
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1001">
<title>Java 核心技术</title>
<author>凯·霍斯特曼</author>
<price>149.00</price>
</book>
<book id="1002">
<title>深入理解 Java 虚拟机</title>
<author>周志明</author>
<price>129.00</price>
</book>
<book id="1003">
<title>Effective Java</title>
<author>Joshua Bloch</author>
<price>99.00</price>
</book>
</bookstore>
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="bookstore">
<xs:complexType>
<xs:sequence>
<xs:element name="book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
合法文档运行:
java -cp $CP SchemaValidateXerces books.xml books.xsd
实测回显:
校验结果: 通过,books.xml 符合 books.xsd 定义的规则。
构造违例文档 books-invalid.xml(price 写成"免费"、第二本书删掉 author):
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1001">
<title>Java 核心技术</title>
<author>凯·霍斯特曼</author>
<price>免费</price>
</book>
<book id="1002">
<title>深入理解 Java 虚拟机</title>
<price>129.00</price>
</book>
</bookstore>
java -cp $CP SchemaValidateXerces books-invalid.xml books.xsd
实测回显:
[错误] 第6行: cvc-datatype-valid.1.2.1: '免费' is not a valid value for 'decimal'.
[错误] 第6行: cvc-type.3.1.3: The value '免费' of element 'price' is not valid.
[错误] 第10行: cvc-complex-type.2.4.a: Invalid content was found starting with element 'price'. One of '{author}' is expected.
校验结果: 未通过,共发现 3 处校验错误。
对带命名空间的文档改用 external-schemaLocation property,值为"命名空间URI 空格 Schema位置"对(探针实测 setProperty 成功并读回 http://example.com/store books.xsd,见第四章)。
5.4 schema-full-checking:Schema 全检查
默认 false 时,Schema 编译只做常规检查;开启后额外执行完整约束集,典型可捕获 UPA(Unique Particle Attribution,唯一粒子归属)违例。构造一个歧义内容模型 upa.xsd(两个分支都以 circle 开头)与实例 upa.xml:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="shape">
<xs:complexType>
<xs:choice>
<xs:sequence>
<xs:element name="circle"/>
<xs:element name="label"/>
</xs:sequence>
<xs:sequence>
<xs:element name="circle"/>
</xs:sequence>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>
<shape><circle/></shape>
测试程序同样复用 5.1 骨架,核心差异只有一行(在 5.3 的参数基础上追加全检查开关):
parser.setFeature("http://xml.org/sax/features/validation", true);
parser.setFeature("http://apache.org/xml/features/validation/schema", true);
parser.setFeature("http://apache.org/xml/features/validation/schema-full-checking", full); // 本节主角
parser.setProperty("http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
"upa.xsd");
默认(false)运行:
java -cp $CP FullCheckDemo false
实测回显:
[错误] cvc-complex-type.2.4.b: The content of element 'shape' is not complete. One of '{label}' is expected.
共发现 1 处错误。
(本次 schema-full-checking feature = false)
开启全检查运行:
java -cp $CP FullCheckDemo true
实测回显:
[错误] cvc-complex-type.2.4.b: The content of element 'shape' is not complete. One of '{label}' is expected.
[错误] cos-nonambig: circle and circle (or elements from their substitution group) violate "Unique Particle Attribution". During validation against this schema, ambiguity would be created for those two particles.
共发现 2 处错误。
(本次 schema-full-checking feature = true)
验证结论:cos-nonambig 这类 Schema 设计期错误只有全检查开启才会报告。 Schema 发布前的质量门禁建议开启此参数(代价是 Schema 编译变慢)。
补充一个相关开关 http://apache.org/xml/features/validation/dynamic(默认 false,探针实测可设置并读回 true):开启后解析器按文档自身"有无校验依据"决定是否校验——带 DOCTYPE 就做 DTD 校验、带 xsi:noNamespaceSchemaLocation 就做 Schema 校验、都没有则只查良构;与显式开启 validation 的区别是"没有依据时静默跳过而非报错"。
5.5 disallow-doctype-decl:禁止 DOCTYPE(XXE 防护核心)
开启后文档一出现 DOCTYPE 声明立即致命错误,是最干脆的 XXE 防线。测试文档 doctest.xml(内部实体):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE memo [
<!ENTITY greeting "你好,Xerces">
]>
<memo><msg>&greeting;</msg></memo>
测试程序:
import org.apache.xerces.parsers.SAXParser;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class DoctypeDemo {
public static void main(String[] args) throws Exception {
boolean disallow = Boolean.parseBoolean(args[0]);
SAXParser parser = new SAXParser();
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disallow);
try {
parser.parse(args[1]);
System.out.println("解析完成,未抛出致命错误。");
} catch (SAXException e) {
System.out.println("解析中止,SAXException: " + e.getMessage());
}
System.out.println("(本次 disallow-doctype-decl feature = " + disallow + ")");
}
}
开启运行:
java -cp $CP DoctypeDemo true doctest.xml
实测回显:
[Fatal Error] doctest.xml:2:10: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.
解析中止,SAXException: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.
(本次 disallow-doctype-decl feature = true)
默认(false)运行:
java -cp $CP DoctypeDemo false doctest.xml
实测回显:
解析完成,未抛出致命错误。
(本次 disallow-doctype-decl feature = false)
💡 技术拓展:XXE(XML External Entity,XML 外部实体注入)是解析不受信 XML 的头号风险,防线从强到弱——
防线 做法 取舍 禁 DOCTYPE disallow-doctype-decl=true 最彻底,但合法使用 DOCTYPE 的文档会被拒 禁外部实体加载 load-external-dtd=false 等 保留 DOCTYPE 语法,禁外部取数 限制实体展开 setSecurityManager(实体数/展开上限) 兼容性最好,防"实体炸弹"递归放大 生产解析外部来源 XML 时,本文采用"禁 DOCTYPE 为主、禁外部加载为辅"的组合,见第六章模板。
5.6 load-external-dtd:外部 DTD 加载
默认 true:即使不做校验,遇到外部 DTD 声明也会去加载。测试文档 extdtd.xml 引用一个不存在的 missing.dtd:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note SYSTEM "missing.dtd">
<note>
<to>张三</to>
</note>
测试程序复用 5.1 骨架,核心片段(注意补捕获 parse() 声明的 IOException,现象见下):
boolean load = Boolean.parseBoolean(args[0]);
SAXParser parser = new SAXParser();
parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", load);
parser.setErrorHandler(handler); // 与 5.1 相同的 ErrorHandler
try {
parser.parse(args[1]);
System.out.println("解析流程结束。");
} catch (SAXException e) {
System.out.println("解析中止(SAXException): " + e.getMessage());
} catch (java.io.IOException e) {
System.out.println("解析中止(IOException): " + e);
}
默认(true)运行:
java -cp $CP LoadDtdDemo true extdtd.xml
实测回显:
解析中止(IOException): java.io.FileNotFoundException: /root/xerces-lab/src/missing.dtd (No such file or directory)
(本次 load-external-dtd feature = true)
关闭运行:
java -cp $CP LoadDtdDemo false extdtd.xml
实测回显:
解析流程结束。
(本次 load-external-dtd feature = false)
验证结论:外部 DTD 加载失败抛的是 IOException(不是 SAX 校验错误,ErrorHandler 拦不住);关闭该参数后解析器根本不去碰 missing.dtd。这个参数同时是性能参数(省一次文件/网络 IO)与安全参数(切断外部引用)。
5.7 JAXP 标准 property:schemaLanguage / schemaSource
这两个 property 是 JAXP 规范定义的可移植写法(不依赖 http://apache.org 前缀),设置在 javax.xml.parsers.SAXParser 实例上。探针实测(PropertyProbe 基于 org.apache.xerces.parsers.SAXParser,同样接受这两个 URI):
setProperty 成功: http://java.sun.com/xml/jaxp/properties/schemaLanguage = http://www.w3.org/2001/XMLSchema
getProperty 读回: http://www.w3.org/2001/XMLSchema
setProperty 成功: http://java.sun.com/xml/jaxp/properties/schemaSource = books.xsd
getProperty 读回: books.xsd
完整的 JAXP 路线校验程序与实测输出见《Apache Xerces-J 在 Ubuntu 22.04 集成使用指南》第五章(schemaLanguage 设为 http://www.w3.org/2001/XMLSchema,schemaSource 传 Schema 文件路径,实测输出为三行 cvc-* 错误与"未通过,共发现 3 处校验错误")。
六、生产配置模板
适用场景:后端服务解析外部提交的 XML(如导入、回调报文),单机 2C4G,要求防 XXE 且按 Schema 强校验。
import org.apache.xerces.parsers.SAXParser;
public class SafeXmlParser {
public static SAXParser createSafeParser() throws Exception {
SAXParser parser = new SAXParser();
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
parser.setFeature("http://xml.org/sax/features/validation", true);
parser.setFeature("http://apache.org/xml/features/validation/schema", true);
parser.setProperty(
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
"books.xsd");
return parser;
}
}
逐项说明:第一行禁 DOCTYPE(外部报文不需要 DOCTYPE,直接拒收);第二行兜底禁外部 DTD 加载;第三、四行开启 Schema 校验;最后一行把 Schema 钉在本服务自带的 books.xsd 上,不信任报文里声明的 xsi:schemaLocation。所有参数均已在前文逐项实测验证。
七、常见问题
Q1:setFeature 抛 SAXNotRecognizedException 是什么原因? 三种可能:URI 拼错(大小写敏感,逐字符核对第四章总览表);把 Xerces 专有参数设到了 JDK 内置实现的老版本上;参数设置到了不支持它的解析器包装类。先用探针程序对目标解析器实测该 URI。
Q2:明明开了校验却不报错? 依次检查:validation 与 validation/schema 是否同时开启(Schema 校验两者都要);Schema 来源是否设置成功(external-noNamespaceSchemaLocation 或 schemaSource property);错误处理器是否覆盖 error() 回调——校验错误走 error() 而不是抛异常,不重抛、不计数就会"看起来通过"。
Q3:property 设置报 SAXNotSupportedException? 典型场景是 Schema 校验未开启时设置 schemaSource 类 property,或在解析进行中改参数。原则:所有 feature/property 都在 parse() 之前设置完成。
Q4:外部 DTD 找不到,为什么 ErrorHandler 里看不到? 外部实体加载失败抛 IOException(实测见 5.6),不是 SAXParseException。捕获 parse() 声明的 IOException 并单独处理。
八、参考链接
- Xerces-J features 官方列表:https://xerces.apache.org/xerces2-j/features.html
- Xerces-J properties 官方列表:https://xerces.apache.org/xerces2-j/properties.html
- SAX 标准接口:https://www.saxproject.org/
- 本文配套篇目:《Apache Xerces-J 在 Ubuntu 22.04 集成使用指南》《Apache Xerces-J 2.12.2 命令行工具详解》