Apache XMLSchema 在 Ubuntu 22.04 集成使用指南
在 Ubuntu 22.04 服务器上从零引入 Apache XMLSchema(org.apache.ws.xmlschema:xmlschema-core 2.3.3)的完整集成指南,覆盖依赖引入、XSD 加载、对象树遍历、JAXP 校验联动与编程建模,全部示例实测通过。
Apache XMLSchema 在 Ubuntu 22.04 集成使用指南
目标:在 Ubuntu 22.04 服务器上从零完成 Apache XMLSchema(xmlschema-core)的依赖引入,跑通「加载 XSD → 对象树遍历 → JAXP 校验联动 → 编程建模」四组可独立执行的示例。全部命令与回显在 Ubuntu 22.04.5 LTS + OpenJDK 17 + Maven 3.6.3 环境实测通过。
一、环境信息
本章列出实测环境的完整信息,照做即可复现。操作系统与工具链:
grep PRETTY_NAME /etc/os-release
实测输出:
PRETTY_NAME="Ubuntu 22.04.5 LTS"
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)
mvn -version | head -3
实测输出:
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
本文使用的依赖与示例文件统一放在 /root/demo 下,XMLSchema 构件版本为 Maven Central 当前最新稳定版 2.3.3(版本选型依据见《Apache XMLSchema 介绍与选型指南》)。
二、前置条件
本库是纯 Java 库(无独立进程、无 CLI),前置只有 JDK 与 Maven 两样。在全新服务器上安装:
apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk maven
实测输出(节选,安装包较多时全量输出很长):
Processing triggers for libgdk-pixbuf-2.0-0:amd64 (2.42.8+dfsg-1ubuntu0.5) ...
安装后验证(务必用回显确认版本,不要凭印象):
java -version 2>&1 | head -1 && mvn -version | head -1
实测输出:
openjdk version "17.0.20.1" 2026-08-18
Apache Maven 3.6.3
⚠️ 注意:服务器会话必须是 UTF-8 locale。实测中默认 locale 下程序输出的中文全部变成问号(见第六章排障),执行示例前先固定编码:
export LANG=C.UTF-8 LC_ALL=C.UTF-8
该命令无回显,属正常。创建工程目录结构:
mkdir -p /root/demo/src/main/java/com/example /root/demo/schemas /root/demo/xml /root/demo/out && cd /root/demo
该命令无回显。创建完工程骨架后,最终文件清单如下(find 验证):
find . -type f | sort
实测输出:
./pom.xml
./schemas/company.xsd
./src/main/java/com/example/BuildSchema.java
./src/main/java/com/example/JaxpValidate.java
./src/main/java/com/example/LoadAndTraverse.java
./xml/employee-invalid.xml
./xml/employee-valid.xml
三、依赖引入
在 /root/demo/pom.xml 中写入如下内容(编辑器创建该文件):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>xmlschema-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.ws.xmlschema</groupId>
<artifactId>xmlschema-core</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
</project>
坐标逐项说明:groupId 为 org.apache.ws.xmlschema、artifactId 为 xmlschema-core,这是 2.x 时代唯一的正式构件(1.x 时代的 xmlschema 构件已淘汰);版本 2.3.3 是 Maven Central maven-metadata.xml 的 <release> 实测值。该构件零传递依赖(《介绍与选型指南》有依赖树实测),不会拖入其他 jar。
编译验证依赖可用:
mvn -q compile; echo COMPILE_EXIT=$?
实测输出:
COMPILE_EXIT=0
mvn dependency:tree 2>&1 | sed -n '/maven-dependency-plugin/,/BUILD/p' | head -6
实测输出:
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ xmlschema-demo ---
[INFO] com.example:xmlschema-demo:jar:1.0.0
[INFO] \- org.apache.ws.xmlschema:xmlschema-core:jar:2.3.3:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
💡 说明:
exec-maven-plugin用于直接运行示例类的 main 方法(后文mvn exec:java命令),首次运行会自动下载该插件,无需在 POM 里声明版本。
四、核心 API/配置
本章先给出后续示例要用的四个 API 入口,理解了再进第五章动手。
4.1 XmlSchemaCollection:集合入口
XmlSchemaCollection 是一切操作的起点,负责读 XSD、解析 import/include、跨 schema 查找。它的读取入口是一组重载的 read(...):接受 javax.xml.transform.Source、SAX InputSource、Reader、DOM Document/Element 等多种输入(重载清单可用 javap -cp <jar路径> org.apache.ws.commons.schema.XmlSchemaCollection 自查,其中 read(Source) 与 read(InputSource) 是文件场景最常用的两个)。查找类方法三个:getElementByQName(QName)/getTypeByQName(QName) 做集合级深查找,getXmlSchemas() 返回集合内全部 schema。解析策略由 setSchemaResolver(URIResolver) 注入,可对 xsd:include/xsd:import 的定位做重定向(内网离线场景的标准做法,实测见《Apache XMLSchema 2.3.3 配置参数详解》5.6 节)。
4.2 XmlSchema:单文档模型
read() 返回的 XmlSchema 对应一个 XSD 文档。常用取值方法:getTargetNamespace()(目标命名空间)、getElements()(全局元素 Map)、getSchemaTypes()(全局类型 Map)、getItems()(声明顺序的原始列表)、getElementByName()/getTypeByName()(按名查找)、write()(重新序列化)。
4.3 读取的关键参数:systemId
read(Source) 时必须给 StreamSource 设置 systemId(文件 URI),否则 XSD 里 xsd:include/xsd:import 的相对路径没有解析基准,直接解析失败。这是本库最常见的新手坑,本章示例统一用 xsd.toURI().toString() 设置。
💡 技术拓展:
systemId是 XML 规范里的「系统标识符」,即文档的 URI 基准。JAXP 全家桶(SAXParser、Validator、XmlSchemaCollection)的相对路径解析都依赖它。给法有两种:source.setSystemId(file.toURI().toString())(推荐,跨目录稳定)或集合级collection.setBaseUri(dir)(给整个集合一个基准目录)。本文用前者。
4.4 线程与可变性
XmlSchemaCollection 内部是普通可变 Map,非线程安全;同一集合跨线程共享时需外部同步或只读使用。2.3.x 可用系统属性 org.apache.ws.commons.schema.protectReadOnlyCollections=true 让返回的集合视图只读化(实测见《Apache XMLSchema 2.3.3 配置参数详解》)。
五、集成示例
本章四组示例可独立执行:先给被解析的 XSD 与实例文档,再逐组给源码、运行命令与完整实测输出。
5.1 示例用 XSD:company.xsd
/root/demo/schemas/company.xsd 内容(编辑器创建):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:co="http://example.com/company"
targetNamespace="http://example.com/company"
elementFormDefault="qualified">
<!-- 1. 全局简单类型:员工编号,用 pattern 限定格式 -->
<xs:simpleType name="EmployeeIdType">
<xs:restriction base="xs:string">
<xs:pattern value="EMP-[0-9]{4}"/>
</xs:restriction>
</xs:simpleType>
<!-- 2. 全局复杂类型:员工 -->
<xs:complexType name="EmployeeType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="id" type="co:EmployeeIdType"/>
<xs:element name="salary" type="xs:decimal" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="grade" type="xs:int" use="required"/>
</xs:complexType>
<!-- 3. 全局元素:employee 引用全局类型 -->
<xs:element name="employee" type="co:EmployeeType"/>
<!-- 4. 全局元素:company,匿名复杂类型 + ref 引用 employee -->
<xs:element name="company">
<xs:complexType>
<xs:sequence>
<xs:element ref="co:employee" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
配套实例文档 /root/demo/xml/employee-valid.xml(注意属性 grade 不带前缀,原因见 5.3 的坑位说明):
<?xml version="1.0" encoding="UTF-8"?>
<co:company xmlns:co="http://example.com/company">
<co:employee grade="5">
<co:name>张三</co:name>
<co:id>EMP-0001</co:id>
<co:salary>12000.50</co:salary>
</co:employee>
<co:employee grade="3">
<co:name>李四</co:name>
<co:id>EMP-0002</co:id>
</co:employee>
</co:company>
/root/demo/xml/employee-invalid.xml(id 违反 pattern、缺 grade 属性,用于演示校验失败):
<?xml version="1.0" encoding="UTF-8"?>
<co:company xmlns:co="http://example.com/company">
<co:employee>
<co:name>王五</co:name>
<co:id>EMP-12</co:id>
</co:employee>
</co:company>
5.2 示例一:加载 XSD 并遍历元素/类型/属性
/root/demo/src/main/java/com/example/LoadAndTraverse.java:
package com.example;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaAttribute;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.apache.ws.commons.schema.XmlSchemaComplexType;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaFacet;
import org.apache.ws.commons.schema.XmlSchemaObject;
import org.apache.ws.commons.schema.XmlSchemaParticle;
import org.apache.ws.commons.schema.XmlSchemaSequence;
import org.apache.ws.commons.schema.XmlSchemaSequenceMember;
import org.apache.ws.commons.schema.XmlSchemaSimpleType;
import org.apache.ws.commons.schema.XmlSchemaSimpleTypeContent;
import org.apache.ws.commons.schema.XmlSchemaSimpleTypeRestriction;
import org.apache.ws.commons.schema.XmlSchemaType;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.util.Map;
/**
* E1 主示例:加载 XSD -> XmlSchemaCollection/XmlSchema 对象 -> 遍历元素/类型/属性。
*/
public class LoadAndTraverse {
public static void main(String[] args) throws Exception {
File xsd = new File(args[0]);
XmlSchemaCollection collection = new XmlSchemaCollection();
// 关键点:StreamSource 必须设置 systemId,xsd:include/xsd:import 的相对路径
// 才有解析基准;这里用 file URI 指向文件本身
StreamSource source = new StreamSource(xsd);
source.setSystemId(xsd.toURI().toString());
XmlSchema schema = collection.read(source);
System.out.println("== 1. 模型基本信息 ==");
System.out.println("targetNamespace = " + schema.getTargetNamespace());
System.out.println("logicalTargetNS = " + schema.getLogicalTargetNamespace());
System.out.println("elementFormDefault = " + schema.getElementFormDefault());
System.out.println("attributeFormDefault = " + schema.getAttributeFormDefault());
System.out.println("inputEncoding = " + schema.getInputEncoding());
System.out.println("getItems().size() = " + schema.getItems().size());
System.out.println("collection.getXmlSchemas().length = " + collection.getXmlSchemas().length);
System.out.println();
System.out.println("== 2. 全局元素(schema.getElements())==");
for (Map.Entry<QName, XmlSchemaElement> e : schema.getElements().entrySet()) {
XmlSchemaElement el = e.getValue();
System.out.printf(" 元素 %-12s 类型=%-30s 匿名类型=%s nillable=%s%n",
e.getKey(), String.valueOf(el.getSchemaTypeName()),
el.getSchemaType() != null && el.getSchemaTypeName() == null,
el.isNillable());
}
System.out.println();
System.out.println("== 3. 全局类型(schema.getSchemaTypes())==");
for (Map.Entry<QName, XmlSchemaType> t : schema.getSchemaTypes().entrySet()) {
System.out.println(" 类型 " + t.getKey() + " -> " + t.getValue().getClass().getSimpleName());
}
System.out.println();
System.out.println("== 4. 集合级查找 API(深查找,覆盖 import 进来的 schema)==");
QName empQ = new QName(schema.getTargetNamespace(), "employee");
XmlSchemaElement found = collection.getElementByQName(empQ);
System.out.println("collection.getElementByQName(employee) = " + found.getName()
+ "(类型 " + found.getSchemaTypeName() + ")");
XmlSchemaType empType = collection.getTypeByQName(
new QName(schema.getTargetNamespace(), "EmployeeType"));
System.out.println("collection.getTypeByQName(EmployeeType) = " + empType.getClass().getSimpleName());
System.out.println();
System.out.println("== 5. 复杂类型深遍历(sequence 子元素 / 属性 / 简单类型约束)==");
walkType(schema, "EmployeeType");
walkType(schema, "EmployeeIdType");
System.out.println();
System.out.println("== 6. 匿名复杂类型(company 元素内联定义)==");
XmlSchemaElement company = schema.getElementByName("company");
XmlSchemaComplexType anon = (XmlSchemaComplexType) company.getSchemaType();
System.out.println("company.getSchemaType() = " + anon.getClass().getSimpleName()
+ ",匿名类型 QName = " + anon.getQName());
XmlSchemaParticle p = anon.getParticle();
XmlSchemaSequence seq = (XmlSchemaSequence) p;
for (XmlSchemaSequenceMember o : seq.getItems()) {
XmlSchemaElement ref = (XmlSchemaElement) o;
System.out.printf(" sequence 子项 name=%-9s ref指向=%-40s maxOccurs=%d%n",
ref.getName(), String.valueOf(ref.getTargetQName()), ref.getMaxOccurs());
}
}
/** 按「序列子元素 + 属性」两层遍历复杂类型;简单类型则打印 restriction 约束面。 */
static void walkType(XmlSchema schema, String typeName) {
XmlSchemaType type = schema.getTypeByName(typeName);
System.out.println("[" + typeName + "] " + type.getClass().getSimpleName());
if (type instanceof XmlSchemaComplexType) {
XmlSchemaComplexType ct = (XmlSchemaComplexType) type;
XmlSchemaParticle particle = ct.getParticle();
if (particle instanceof XmlSchemaSequence) {
XmlSchemaSequence s = (XmlSchemaSequence) particle;
// 注意:getItems() 返回 List<XmlSchemaSequenceMember>(元素/any 的公共接口),
// 需要转成 XmlSchemaElement 才能取元素属性
for (XmlSchemaSequenceMember o : s.getItems()) {
XmlSchemaElement el = (XmlSchemaElement) o;
System.out.printf(" 序列子元素 %-9s 类型=%-28s minOccurs=%d maxOccurs=%d%n",
el.getName(), String.valueOf(el.getSchemaTypeName()),
el.getMinOccurs(), el.getMaxOccurs());
}
}
for (XmlSchemaObject o : ct.getAttributes()) {
XmlSchemaAttribute at = (XmlSchemaAttribute) o;
System.out.printf(" 属性 %-8s use=%-9s 类型=%s%n",
at.getName(), at.getUse(), at.getSchemaTypeName());
}
} else if (type instanceof XmlSchemaSimpleType) {
XmlSchemaSimpleType st = (XmlSchemaSimpleType) type;
XmlSchemaSimpleTypeContent content = st.getContent();
if (content instanceof XmlSchemaSimpleTypeRestriction) {
XmlSchemaSimpleTypeRestriction r = (XmlSchemaSimpleTypeRestriction) content;
System.out.println(" restriction base=" + r.getBaseTypeName());
for (XmlSchemaFacet f : r.getFacets()) {
System.out.println(" 约束面 " + f.getClass().getSimpleName()
+ " value=" + f.getValue());
}
}
}
}
}
运行:
mvn -q exec:java -Dexec.mainClass=com.example.LoadAndTraverse -Dexec.args='schemas/company.xsd'
实测输出(完整):
== 1. 模型基本信息 ==
targetNamespace = http://example.com/company
logicalTargetNS = http://example.com/company
elementFormDefault = qualified
attributeFormDefault = unqualified
inputEncoding = UTF-8
getItems().size() = 4
collection.getXmlSchemas().length = 2
== 2. 全局元素(schema.getElements())==
元素 {http://example.com/company}employee 类型={http://example.com/company}EmployeeType 匿名类型=false nillable=false
元素 {http://example.com/company}company 类型=null 匿名类型=true nillable=false
== 3. 全局类型(schema.getSchemaTypes())==
类型 {http://example.com/company}EmployeeIdType -> XmlSchemaSimpleType
类型 {http://example.com/company}EmployeeType -> XmlSchemaComplexType
== 4. 集合级查找 API(深查找,覆盖 import 进来的 schema)==
collection.getElementByQName(employee) = employee(类型 {http://example.com/company}EmployeeType)
collection.getTypeByQName(EmployeeType) = XmlSchemaComplexType
== 5. 复杂类型深遍历(sequence 子元素 / 属性 / 简单类型约束)==
[EmployeeType] XmlSchemaComplexType
序列子元素 name 类型={http://www.w3.org/2001/XMLSchema}string minOccurs=1 maxOccurs=1
序列子元素 id 类型={http://example.com/company}EmployeeIdType minOccurs=1 maxOccurs=1
序列子元素 salary 类型={http://www.w3.org/2001/XMLSchema}decimal minOccurs=0 maxOccurs=1
属性 grade use=required 类型={http://www.w3.org/2001/XMLSchema}int
[EmployeeIdType] XmlSchemaSimpleType
restriction base={http://www.w3.org/2001/XMLSchema}string
约束面 XmlSchemaPatternFacet value=EMP-[0-9]{4}
== 6. 匿名复杂类型(company 元素内联定义)==
company.getSchemaType() = XmlSchemaComplexType,匿名类型 QName = null
sequence 子项 name=null ref指向={http://example.com/company}employee maxOccurs=9223372036854775807
结果解读:输出里有三个值得注意的真实行为。其一,getXmlSchemas().length = 2——只读了一个文件却是 2 个 schema,因为集合初始化时预建了「XML Schema 命名空间自身」的模型对象;其二,company 元素类型为 null 但匿名类型为 true,即内联定义的类型没有 QName,必须走 getSchemaType() 拿对象;其三,maxOccurs=9223372036854775807 就是 xs:unbounded 的 long 表示(Long.MAX_VALUE)。
5.3 示例二:与 JAXP 联动校验实例文档
xmlschema-core 只建模 XSD,实例文档校验交给 JDK 自带的 JAXP Validator。/root/demo/src/main/java/com/example/JaxpValidate.java:
package com.example;
import org.xml.sax.SAXParseException;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
/**
* E1 联动示例:XmlSchemaCollection 只建模信息集,实例文档校验交给 JAXP Validator。
*/
public class JaxpValidate {
public static void main(String[] args) throws Exception {
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema jaxpSchema = sf.newSchema(new File(args[0]));
Validator validator = jaxpSchema.newValidator();
try {
validator.validate(new StreamSource(new File(args[1])));
System.out.println("校验通过:" + args[1] + " 符合 " + args[0]);
} catch (SAXParseException e) {
System.out.println("校验失败:" + args[1]);
System.out.println(" 位置:第 " + e.getLineNumber() + " 行,第 " + e.getColumnNumber() + " 列");
System.out.println(" 原因:" + e.getMessage());
}
}
}
先校验合法文档:
mvn -q exec:java -Dexec.mainClass=com.example.JaxpValidate -Dexec.args='schemas/company.xsd xml/employee-valid.xml'
实测输出:
校验通过:xml/employee-valid.xml 符合 schemas/company.xsd
再校验非法文档:
mvn -q exec:java -Dexec.mainClass=com.example.JaxpValidate -Dexec.args='schemas/company.xsd xml/employee-invalid.xml'
实测输出:
校验失败:xml/employee-invalid.xml
位置:第 3 行,第 16 列
原因:cvc-complex-type.4: Attribute 'grade' must appear on element 'co:employee'.
⚠️ 注意(实测踩坑):最初实例文档里把属性写成
co:grade="5",校验报cvc-complex-type.3.2.2: Attribute 'co:grade' is not allowed to appear in element 'co:employee'。原因是 XSD 的elementFormDefault="qualified"只约束元素,属性默认attributeFormDefault="unqualified",所以实例中属性必须裸写grade="5"。要么改实例(本文做法),要么在 XSD 上显式声明attributeFormDefault="qualified"。
5.4 示例三:对象级建模(从零构造 XSD)
不读文件,直接用对象模型构造一个 XSD 并序列化输出。/root/demo/src/main/java/com/example/BuildSchema.java:
package com.example;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.apache.ws.commons.schema.XmlSchemaComplexType;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaForm;
import org.apache.ws.commons.schema.XmlSchemaSequence;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import java.io.ByteArrayOutputStream;
/**
* E1 补充示例:用对象模型从零构造一个 XSD(编程建模),并序列化为 XML。
*/
public class BuildSchema {
public static void main(String[] args) throws Exception {
XmlSchemaCollection collection = new XmlSchemaCollection();
// 1. 在集合上创建一个新 schema(targetNamespace 编程指定)
XmlSchema schema = new XmlSchema("http://example.com/built", collection);
schema.setElementFormDefault(XmlSchemaForm.QUALIFIED);
// 2. 全局复杂类型 GreetingType:一个 sequence,只有一个 name 子元素
// 注意:topLevel=true 时构造器已自动把类型注册进 schema,无需再手动 add
XmlSchemaComplexType type = new XmlSchemaComplexType(schema, true);
type.setName("GreetingType");
XmlSchemaSequence seq = new XmlSchemaSequence();
XmlSchemaElement name = new XmlSchemaElement(schema, false);
name.setName("name");
name.setSchemaTypeName(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "string"));
name.setMinOccurs(1);
name.setMaxOccurs(1);
seq.getItems().add(name);
type.setParticle(seq);
// 3. 全局元素 greeting 引用该类型(topLevel=true,同样自动注册)
XmlSchemaElement greeting = new XmlSchemaElement(schema, true);
greeting.setName("greeting");
greeting.setSchemaTypeName(new QName("http://example.com/built", "GreetingType"));
// 4. 序列化输出
ByteArrayOutputStream bos = new ByteArrayOutputStream();
schema.write(bos);
System.out.println(new String(bos.toByteArray(), "UTF-8"));
}
}
运行:
mvn -q exec:java -Dexec.mainClass=com.example.BuildSchema
实测输出(完整):
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://example.com/built" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://example.com/built">
<complexType name="GreetingType">
<sequence>
<element name="name" type="string"/>
</sequence>
</complexType>
<element name="greeting" type="tns:GreetingType"/>
</schema>
⚠️ 注意(实测踩坑):构件构造器第二个参数
topLevel传true时,对象会自动注册进 schema 的全局列表;若再手动schema.getItems().add(...),序列化输出中该构件会出现两次(实测复现过:complexType 与 element 各输出两份)。全局构件一律topLevel=true且不再手动 add。
六、注意事项
- 中文输出乱码排障:默认 locale 非 UTF-8 的会话里,示例输出的中文变成问号(实测复现:
== 1. ?????? ==)。解决:export LANG=C.UTF-8 LC_ALL=C.UTF-8后重新运行。若用 systemd 托管自己的应用,同样在Environment=中注入LANG=C.UTF-8。 - systemId 必须设置:所有
read(Source)场景都要source.setSystemId(...),否则含相对 include/import 的 XSD 直接解析失败。 - 序列成员的接口类型:
XmlSchemaSequence.getItems()返回List<XmlSchemaSequenceMember>,按List<XmlSchemaObject>接收会编译失败(实测报错incompatible types: XmlSchemaSequenceMember cannot be converted to XmlSchemaObject),需以成员接口迭代后强转XmlSchemaElement。 - 重复全局元素读取不报错:xmlschema-core 读取时后声明覆盖前声明;同样的 XSD 交给 JAXP
SchemaFactory.newSchema()编译才报sch-props-correct.2。两个工具的容错语义不同,见《Apache XMLSchema 2.3.3 配置参数详解》对照实测。 - 校验职责分工:建模用 XmlSchemaCollection,实例校验用 JAXP Validator;不要试图用前者校验 XML 实例文档。
- 版本对齐:与 CXF/Axis2 同工程时,用
dependencyManagement统一 xmlschema-core 到 2.3.3(CXF 4.1.4 默认传 2.3.2、Axis2 1.8.2 默认传 2.3.0,实测自两者父 POM)。
七、参考链接
- Maven 坐标:https://repo1.maven.org/maven2/org/apache/ws/xmlschema/xmlschema-core/2.3.3/
- javadoc(2.3.3):https://ws.apache.org/commons/xmlschema20/apidocs/
- 源码镜像:https://github.com/apache/ws-xmlschema
- JAXP 校验官方教程:https://docs.oracle.com/javase/tutorial/jaxp/validation/validation.html
- 相关文档:《Apache XMLSchema 介绍与选型指南》《Apache XMLSchema 2.3.3 配置参数详解》