XML 与 Java — JAXP
本章定位 :掌握 JAXP(Java API for XML Processing)的架构——整合 DOM/SAX/StAX/XSLT/Schema 的五合一门面,理解 Factory 模式和可插拔实现机制。
定义与作用
JAXP (Java API for XML Processing)不是一种新的解析技术,而是 Java 标准库中 整合所有 XML 处理 API 的统一门面 。
JAXP 提供了:
- DOM 解析 :
DocumentBuilderFactory→DocumentBuilder - SAX 解析 :
SAXParserFactory→SAXParser - StAX 解析 :
XMLInputFactory/XMLOutputFactory - XSLT 转换 :
TransformerFactory→Transformer - Schema 验证 :
SchemaFactory→Schema→Validator
JAXP 的核心设计是 可插拔——通过 Factory 模式,你写的代码不依赖于具体的解析器实现(如 Xerces),可以在运行时切换。
核心原理:JAXP 架构全景
图解释 :JAXP 是一层抽象门面。应用只依赖 javax.xml.* 接口,具体实现(Xerces/Woodstox/Saxon)通过 ServiceLoader 机制在运行时加载。这种设计让你可以切换实现而不改代码。
语法/结构要点
五大 Factory 对比
| Factory | 产物 | 用途 |
|---|---|---|
DocumentBuilderFactory | DocumentBuilder | DOM 解析(parse → Document) |
SAXParserFactory | SAXParser | SAX 解析(parse → 事件回调) |
XMLInputFactory | XMLStreamReader / XMLEventReader | StAX 读取 |
TransformerFactory | Transformer | XSLT 转换 |
SchemaFactory | Schema → Validator | XSD 验证 |
Schema 验证流程
// 1. 创建 SchemaFactory
SchemaFactory sf = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
// 2. 编译 XSD 为 Schema 对象
Schema schema = sf.newSchema(new File("bookstore.xsd"));
// 3. 创建 Validator
Validator validator = schema.newValidator();
// 4. 设置错误处理器
validator.setErrorHandler(new DefaultHandler() {
public void error(SAXParseException e) {
System.out.println("验证错误: " + e.getMessage());
}
});
// 5. 验证 XML
validator.validate(new StreamSource(new File("bookstore.xml")));
完整示例:白歌整合 JAXP 全套流程
场景说明
飞翔科技的架构师 白歌 为团队封装了一个 XMLProcessor 工具类,支持:读 XML → XSD 验证 → DOM 修改 → XSLT 转换 → 写回文件。
集成代码
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.*;
import javax.xml.validation.*;
import org.w3c.dom.*;
import java.io.File;
public class XMLProcessor {
// ① DOM 读取 + XSD 验证
public static Document parseAndValidate(String xmlPath, String xsdPath)
throws Exception {
// 创建 Schema
SchemaFactory sf = SchemaFactory.newInstance(
"http://www.w3.org/2001/XMLSchema");
Schema schema = sf.newSchema(new File(xsdPath));
// 创建 DOM 解析器并绑定 Schema
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setSchema(schema); // 关键:绑定 XSD 验证
DocumentBuilder db = dbf.newDocumentBuilder();
// 自定义错误处理(解析失败不中断)
db.setErrorHandler(new org.xml.sax.ErrorHandler() {
public void warning(org.xml.sax.SAXParseException e) {
System.out.println("警告: " + e.getMessage());
}
public void error(org.xml.sax.SAXParseException e) {
System.out.println("错误: " + e.getMessage());
}
public void fatalError(org.xml.sax.SAXParseException e)
throws org.xml.sax.SAXException {
throw e; // 致命错误仍然抛出
}
});
Document doc = db.parse(new File(xmlPath));
System.out.println("XML 解析 + XSD 验证完成");
return doc;
}
// ② XSLT 转换
public static void transform(String xmlPath, String xsltPath,
String outputPath) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer(
new StreamSource(new File(xsltPath)));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(
new StreamSource(new File(xmlPath)),
new StreamResult(new File(outputPath))
);
System.out.println("XSLT 转换完成 → " + outputPath);
}
// ③ 保存 DOM 到文件
public static void saveDocument(Document doc, String outputPath)
throws Exception {
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.transform(new DOMSource(doc), new StreamResult(new File(outputPath)));
System.out.println("DOM 已保存 → " + outputPath);
}
public static void main(String[] args) throws Exception {
// 完整流程:解析验证 → 修改 → 保存 → 转换
Document doc = parseAndValidate("students.xml", "students.xsd");
// 业务修改:给所有学生加 processDate 属性
NodeList list = doc.getElementsByTagName("student");
for (int i = 0; i < list.getLength(); i++) {
((Element) list.item(i)).setAttribute(
"processDate", "2024-06-10");
}
saveDocument(doc, "students_verified.xml");
transform("students_verified.xml",
"student_report.xsl",
"report.html");
}
}
操作结果
白歌为团队封装了标准化的 XML 处理流程:
parseAndValidate:读 XML 的同时用 XSD 验证,不合格直接报错transform:将验证后的 XML 用 XSLT 转为 HTML 报告saveDocument:保存 DOM 修改到文件
整个流程只依赖 JDK 标准库(javax.xml.*),无需第三方依赖。
易错场景
错误一:忘记 setNamespaceAware(true)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// ❌ 默认不感知命名空间,XSD 验证失效
dbf.setSchema(schema);
// ✅ 必须先启用命名空间感知
dbf.setNamespaceAware(true);
dbf.setSchema(schema);
错误二:XSLT Transformer 未设置编码
// ❌ 中文可能乱码
Transformer t = TransformerFactory.newInstance().newTransformer(sheet);
t.transform(source, result);
// ✅ 显式设置编码
t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
面试考点
| 考点 | 参考答案要点 |
|---|---|
| JAXP 包含哪些主要 API? | DOM(DocumentBuilder)、SAX(SAXParser)、StAX(XMLStreamReader)、XSLT(Transformer)、Validation(Schema/Validator) |
| JAXP 的 Factory 模式有什么好处? | 代码只依赖 javax.xml.* 接口,具体实现可插拔。通过 ServiceLoader 机制在运行时加载不同厂商的实现(Xerces/Woodstox/Saxon) |
| 如何在 DOM 解析时同时进行 XSD 验证? | ①创建 SchemaFactory → Schema;②DocumentBuilderFactory.setSchema(schema);③setNamespaceAware(true);④builder.parse() |