Java 中 XML 解析与处理全解析
1. SAX 解析 XML 文档
SAX(Simple API for XML)是一种基于事件的 Java API,用于从头到尾顺序解析 XML 文档。当面向 SAX 的解析器遇到文档信息集中的某个项目时,它会通过调用应用程序之前向解析器注册的处理程序中的某个方法,将该项目作为一个事件提供给应用程序,应用程序随后可以以某种方式处理该信息集项目。
以下是使用 SAX 的一些关键步骤和代码示例:
-
获取 SAX 2 解析器
:调用
XMLReaderFactory
类的
createXMLReader()
方法,该方法返回一个
XMLReader
对象。
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class SAXExample {
public static void main(String[] args) {
try {
XMLReader xmlr = XMLReaderFactory.createXMLReader();
} catch (Exception e) {
e.printStackTrace();
}
}
}
-
让 SAX 解析器执行验证
:调用
XMLReader的setFeature(String name, boolean value)方法,将"http://xml.org/sax/features/validation"传递给name,将true传递给value。
xmlr.setFeature("http://xml.org/sax/features/validation", true);
-
SAX 异常类型
:在使用 SAX 时可能会抛出四种类型的异常,分别是
SAXException、SAXNotRecognizedException、SAXNotSupportedException和SAXParseException。 -
处理程序接口
:
-
ContentHandler:处理程序类实现该接口以响应面向内容的事件。 -
DTDHandler、EntityResolver和ErrorHandler:处理程序类可能实现的其他三个核心接口。
-
2. DOM 解析与创建 XML 文档
DOM(Document Object Model)是一种 Java API,用于将 XML 文档解析为内存中的节点树,并从节点树创建 XML 文档。DOM 解析器创建文档树后,应用程序可以使用 DOM API 遍历树的节点并提取信息集项目。
以下是使用 DOM 的关键步骤和代码示例:
-
获取文档构建器
:首先通过
DocumentBuilderFactory
的
newInstance()
方法实例化
DocumentBuilderFactory
,然后在返回的
DocumentBuilderFactory
对象上调用
newDocumentBuilder()
方法以获取
DocumentBuilder
对象。
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
public class DOMExample {
public static void main(String[] args) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
} catch (Exception e) {
e.printStackTrace();
}
}
}
-
使用文档构建器解析 XML 文档
:调用
DocumentBuilder的parse()方法。
import org.w3c.dom.Document;
Document doc = db.parse("your_xml_file.xml");
-
使用文档构建器创建新的 XML 文档
:调用
DocumentBuilder的newDocument()方法,并调用Document的各种 “create” 方法。
Document newDoc = db.newDocument();
- DOM 节点类型 :DOM 有 12 种节点类型,包括属性节点、CDATA 节节点、注释节点等。
3. StAX 解析与创建 XML 文档
StAX(Streaming API for XML)是一种 Java API,用于从头到尾顺序解析 XML 文档,也可用于创建 XML 文档。
以下是使用 StAX 的关键步骤和代码示例:
-
获取文档读取器和写入器
:
- 调用
XMLInputFactory
类中声明的各种 “create” 方法获取文档读取器。
- 调用
XMLOutputFactory
类中声明的各种 “create” 方法获取文档写入器。
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.FileReader;
public class StAXExample {
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("usage: java StAXExample pathname");
return;
}
XMLInputFactory xmlif = XMLInputFactory.newFactory();
try (FileReader fr = new FileReader(args[0])) {
XMLStreamReader xmlsr = xmlif.createXMLStreamReader(fr);
} catch (Exception e) {
e.printStackTrace();
}
}
}
-
处理命名空间
:调用
XMLOutputFactory的setProperty(String name, Object value)方法,将XMLOutputFactory.IS_REPAIRING_NAMESPACES作为属性名,将true作为值,文档写入器将处理所有命名空间绑定和声明,输出在命名空间方面始终格式良好。
4. XPath 选择节点
XPath 是一种非 XML 声明性查询语言(由 W3C 定义),用于将 XML 文档的信息集项目选择为一个或多个节点。
以下是 XPath 的关键特性和代码示例:
-
XPath 节点类型
:XPath 识别七种节点类型,包括元素、属性、文本、命名空间、处理指令、注释和文档。
-
位置路径表达式
:XPath 提供位置路径表达式来选择节点,从上下文节点(根节点或当前文档节点)开始,通过一系列步骤定位节点,返回的节点集可能为空,也可能包含一个或多个节点。
-
XPath 函数和通配符
:
-
函数
:
comment()
、
text()
和
processing-instruction()
分别用于选择注释、文本和处理指令节点。
-
通配符
:
*
通配符匹配任何元素节点,
@*
通配符匹配所有属性节点,
node()
通配符匹配所有节点。
-
XPath 代码示例
:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XPathExample {
public static void main(String[] args) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("contacts.xml");
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
XPathExpression xpe = xp.compile("//contact[city = 'Chicago']/name/text()|" +
"//contact[city = 'Chicago']/Name/text()");
NodeList nodes = (NodeList) xpe.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
5. 总结
| API 名称 | 特点 | 适用场景 |
|---|---|---|
| SAX | 基于事件,顺序解析,内存占用小 | 处理大型 XML 文档,无需随机访问 |
| DOM | 构建内存树,可随机访问 | 需要对文档进行多次遍历和修改 |
| StAX | 流式处理,可解析和创建 | 处理大型 XML 文档,需要灵活控制解析过程 |
| XPath | 选择节点,简化访问 | 快速定位和提取 XML 文档中的特定节点 |
通过以上内容,我们详细介绍了 Java 中使用 SAX、DOM、StAX 和 XPath 进行 XML 解析和处理的方法和技巧。不同的 API 适用于不同的场景,开发者可以根据具体需求选择合适的 API。
以下是一个简单的流程图,展示了 SAX 解析 XML 文档的基本流程:
graph TD;
A[开始] --> B[获取 XMLReader];
B --> C[注册处理程序];
C --> D[解析 XML 文档];
D --> E[处理事件];
E --> F[结束];
在实际应用中,我们可以根据具体需求灵活组合这些 API,以实现高效、准确的 XML 处理。例如,在处理大型 XML 文档时,可以使用 SAX 或 StAX 进行解析,然后使用 XPath 进行节点选择;在需要对文档进行修改时,可以使用 DOM 进行操作。
Java 中 XML 解析与处理全解析
6. 代码示例详解
在前面的介绍中,我们已经给出了各个 API 的基本代码示例,下面将对部分代码示例进行详细解释。
6.1 SAX 解析示例
以下是使用 SAX 解析
tomcat - users.xml
文件的代码示例:
import java.io.FileReader;
import java.io.IOException;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
public class DumpUserInfo {
public static void main(String[] args) {
try {
XMLReader xmlr = XMLReaderFactory.createXMLReader();
Handler handler = new Handler();
xmlr.setContentHandler(handler);
xmlr.parse(new InputSource(new FileReader("tomcat - users.xml")));
} catch (IOException ioe) {
System.err.println("IOE: " + ioe);
} catch (SAXException saxe) {
System.err.println("SAXE: " + saxe);
}
}
}
class Handler extends DefaultHandler {
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if (localName.equals("user")) {
for (int i = 0; i < attributes.getLength(); i++)
System.out.printf("%s = %s%n", attributes.getLocalName(i), attributes.getValue(i));
System.out.println();
}
}
}
-
代码解释
:
-
在
main方法中,首先通过XMLReaderFactory.createXMLReader()获取一个XMLReader对象。 -
创建一个自定义的
Handler对象,并将其设置为XMLReader的内容处理程序。 -
调用
xmlr.parse()方法开始解析tomcat - users.xml文件。 -
在
Handler类中,重写了startElement方法,当遇到user元素时,打印该元素的所有属性。
-
在
6.2 DOM 搜索示例
以下是使用 DOM 搜索
books.xml
文件中特定出版商书籍的代码示例:
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class DOMSearch {
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("usage: java DOMSearch publisher");
return;
}
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("books.xml");
class BookItem {
String title;
String isbn;
}
List<BookItem> bookItems = new ArrayList<BookItem>();
NodeList books = doc.getElementsByTagName("book");
for (int i = 0; i < books.getLength(); i++) {
Element book = (Element) books.item(i);
NodeList children = book.getChildNodes();
String title = "";
for (int j = 0; j < children.getLength(); j++) {
Node child = children.item(j);
if (child.getNodeType() == Node.ELEMENT_NODE) {
if (child.getNodeName().equals("title"))
title = child.getFirstChild().getNodeValue().trim();
else if (child.getNodeName().equals("publisher")) {
if (args[0].equals(child.getFirstChild().getNodeValue().trim())) {
BookItem bookItem = new BookItem();
bookItem.title = title;
NamedNodeMap nnm = book.getAttributes();
Node isbn = nnm.getNamedItem("isbn");
bookItem.isbn = isbn.getNodeValue();
bookItems.add(bookItem);
break;
}
}
}
}
}
for (BookItem bookItem : bookItems)
System.out.println("title = " + bookItem.title + ", isbn = " + bookItem.isbn);
} catch (IOException ioe) {
System.err.println("IOE: " + ioe);
} catch (SAXException saxe) {
System.err.println("SAXE: " + saxe);
} catch (FactoryConfigurationError fce) {
System.err.println("FCE: " + fce);
} catch (ParserConfigurationException pce) {
System.err.println("PCE: " + pce);
}
}
}
-
代码解释
:
-
在
main方法中,首先检查输入参数是否正确。 -
获取
DocumentBuilderFactory和DocumentBuilder对象,然后解析books.xml文件得到Document对象。 -
定义一个内部类
BookItem用于存储书籍信息。 -
遍历所有
book元素,对于每个book元素,找到其title和publisher子元素。 -
如果
publisher元素的文本内容与输入参数匹配,则将该书籍信息添加到bookItems列表中。 - 最后打印出所有匹配的书籍信息。
-
在
7. 不同 API 的性能比较
不同的 XML 解析和处理 API 在性能上有不同的表现,以下是一个简单的性能比较表格:
| API 名称 | 内存占用 | 解析速度 | 灵活性 |
| ---- | ---- | ---- | ---- |
| SAX | 低 | 快 | 低,顺序处理 |
| DOM | 高 | 慢 | 高,可以随机访问和修改 |
| StAX | 低 | 快 | 高,可灵活控制解析过程 |
| XPath | - | - | 高,快速定位节点 |
在选择 API 时,需要综合考虑性能和功能需求。例如,如果处理大型 XML 文档且只需要顺序处理,SAX 或 StAX 是较好的选择;如果需要对文档进行多次修改和随机访问,DOM 更合适。
8. 常见问题及解决方案
在使用这些 API 进行 XML 解析和处理时,可能会遇到一些常见问题,以下是一些问题及解决方案:
-
问题 1:解析 XML 文档时出现
SAXException
或
IOException
-
原因
:文件不存在、文件格式错误、网络问题等。
-
解决方案
:检查文件路径是否正确,确保文件格式符合 XML 规范,检查网络连接。
-
问题 2:DOM 解析时内存溢出
-
原因
:XML 文档过大,DOM 会将整个文档加载到内存中。
-
解决方案
:使用 SAX 或 StAX 进行解析,或者分块处理 XML 文档。
-
问题 3:XPath 表达式无法正确匹配节点
-
原因
:XPath 表达式语法错误、命名空间问题等。
-
解决方案
:检查 XPath 表达式的语法,确保命名空间正确。
9. 总结与展望
通过本文的介绍,我们深入了解了 Java 中使用 SAX、DOM、StAX 和 XPath 进行 XML 解析和处理的方法和技巧。不同的 API 适用于不同的场景,开发者可以根据具体需求选择合适的 API。
在未来的开发中,随着 XML 数据的不断增长和应用场景的不断扩展,对 XML 解析和处理的性能和灵活性要求也会越来越高。我们可以期待这些 API 不断改进和优化,以满足更复杂的需求。
以下是一个简单的流程图,展示了选择合适 XML 处理 API 的基本流程:
graph TD;
A[开始] --> B{文档大小};
B -->|小| C{是否需要随机访问};
B -->|大| D{是否需要灵活控制解析过程};
C -->|是| E[DOM];
C -->|否| F[SAX];
D -->|是| G[StAX];
D -->|否| F;
E --> H{是否需要快速定位节点};
F --> H;
G --> H;
H -->|是| I[XPath];
H -->|否| J[结束];
I --> J;
希望本文能帮助开发者更好地理解和使用 Java 中的 XML 解析和处理 API,在实际开发中能够根据具体需求做出正确的选择。
Java中XML解析与处理全解析
超级会员免费看

被折叠的 条评论
为什么被折叠?



