18、Java 中 XML 解析与处理全解析

Java中XML解析与处理全解析

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();
        }
    }
}
  • 代码解释
    1. main 方法中,首先通过 XMLReaderFactory.createXMLReader() 获取一个 XMLReader 对象。
    2. 创建一个自定义的 Handler 对象,并将其设置为 XMLReader 的内容处理程序。
    3. 调用 xmlr.parse() 方法开始解析 tomcat - users.xml 文件。
    4. 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);
        }
    }
}
  • 代码解释
    1. main 方法中,首先检查输入参数是否正确。
    2. 获取 DocumentBuilderFactory DocumentBuilder 对象,然后解析 books.xml 文件得到 Document 对象。
    3. 定义一个内部类 BookItem 用于存储书籍信息。
    4. 遍历所有 book 元素,对于每个 book 元素,找到其 title publisher 子元素。
    5. 如果 publisher 元素的文本内容与输入参数匹配,则将该书籍信息添加到 bookItems 列表中。
    6. 最后打印出所有匹配的书籍信息。
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,在实际开发中能够根据具体需求做出正确的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值