Java SAX 解析器示例
Java 中的 SAX 解析器提供了解析 XML 文档的 API。SAX 解析器与DOM 解析器不同,因为它不会将完整的 XML 加载到内存中并按顺序读取 xml 文档。
SAX 解析器
javax.xml.parsers.SAXParser
提供使用事件处理程序解析 XML 文档的方法。此类实现XMLReader
接口并提供重载版本的parse()
方法以从文件、InputStream、SAX InputSource 和 String URI 读取 XML 文档。实际的解析由 Handler 类完成。我们需要创建自己的处理程序类来解析 XML 文档。我们需要实现org.xml.sax.ContentHandler
接口来创建自己的处理程序类。此接口包含在事件发生时接收通知的回调方法。例如,StartDocument、EndDocument、StartElement、EndElement、CharacterData 等提供了ContentHandlerorg.xml.sax.helpers.DefaultHandler
接口的默认实现,我们可以扩展此类来创建自己的处理程序。建议扩展此类,因为我们可能只需要实现其中的几个方法。扩展此类将使我们的代码更简洁、更易于维护。
SAX 解析器示例
现在让我们跳到 SAX 解析器示例程序,稍后我将详细解释不同的特性。employees.xml
<?xml version="1.0" encoding="UTF-8"?>
<Employees>
<Employee id="1">
<age>29</age>
<name>Pankaj</name>
<gender>Male</gender>
<role>Java Developer</role>
</Employee>
<Employee id="2">
<age>35</age>
<name>Lisa</name>
<gender>Female</gender>
<role>CEO</role>
</Employee>
<Employee id="3">
<age>40</age>
<name>Tom</name>
<gender>Male</gender>
<role>Manager</role>
</Employee>
<Employee id="4">
<age>25</age>
<name>Meghna</name>
<gender>Female</gender>
<role>Manager</role>
</Employee>
</Employees>
因此,我们在文件系统的某个地方存储了一个 XML 文件,通过查看它,我们可以得出结论,它包含员工列表。每个员工都有属性id
和字段age
、name
和。我们将使用 SAX 解析器来解析此 XML 并创建一个员工对象列表。以下是从 XML 中表示员工元素的 Employee 对象。gender
role
package com.journaldev.xml;
public class Employee {
private int id;
private String name;
private String gender;
private int age;
private String role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public String toString() {
return "Employee:: ID="+this.id+" Name=" + this.name + " Age=" + this.age + " Gender=" + this.gender +
" Role=" + this.role;
}
}
让我们创建自己的 SAX Parser Handler 类来扩展DefaultHandler类。
package com.journaldev.xml.sax;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.journaldev.xml.Employee;
public class MyHandler extends DefaultHandler {
// List to hold Employees object
private List<Employee> empList = null;
private Employee emp = null;
private StringBuilder data = null;
// getter method for employee list
public List<Employee> getEmpList() {
return empList;
}
boolean bAge = false;
boolean bName = false;
boolean bGender = false;
boolean bRole = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("Employee")) {
// create a new Employee and put it in Map
String id = attributes.getValue("id");
// initialize Employee object and set id attribute
emp = new Employee();
emp.setId(Integer.parseInt(id));
// initialize list
if (empList == null)
empList = new ArrayList<>();
} else if (qName.equalsIgnoreCase("name")) {
// set boolean values for fields, will be used in setting Employee variables
bName = true;
} else if (qName.equalsIgnoreCase("age")) {
bAge = true;
} else if (qName.equalsIgnoreCase("gender")) {
bGender = true;
} else if (qName.equalsIgnoreCase("role")) {
bRole = true;
}
// create the data container
data = new StringBuilder();
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (bAge) {
// age element, set Employee age
emp.setAge(Integer.parseInt(data.toString()));
bAge = false;
} else if (bName) {
emp.setName(data.toString());
bName = false;
} else if (bRole) {
emp.setRole(data.toString());
bRole = false;
} else if (bGender) {
emp.setGender(data.toString());
bGender = false;
}
if (qName.equalsIgnoreCase("Employee")) {
// add Employee object to list
empList.add(emp);
}
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
data.append(new String(ch, start, length));
}
}
MyHandler 包含对象列表,Employee
作为仅具有 getter 方法的字段。Employee
对象被添加到事件处理程序方法中。此外,我们有一个 Employee 字段,它将用于创建 Employee 对象,一旦设置了所有字段,就将其添加到员工列表中。
要覆盖的 SAX 解析器方法
要重写的重要方法是startElement()
、endElement()
和characters()
。SAXParser
开始解析文档,当找到任何起始元素时,startElement()
就会调用方法。我们重写这个方法来设置用于标识元素的布尔变量。每次找到 Employee 起始元素时,我们还使用此方法创建一个新的 Employee 对象。检查这里如何读取 id 属性来设置 Employee 对象字段。当id
SAXParsercharacters()
在元素内找到字符数据时,会调用方法。请注意,SAX 解析器可能会将数据分成多个块并characters()
多次调用方法(阅读 ContentHandler 类 characters() 方法文档)。这就是为什么我们使用 StringBuilder 通过 append() 方法保存这些数据的原因。在这里,我们使用 StringBuilderendElement()
数据来设置 employee 对象属性,并在找到 Employee 结束元素标记时将 Employee 对象添加到列表中。下面是用于将上述 XML 解析为 Employee 对象列表的测试程序MyHandler
。
package com.journaldev.xml.sax;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import com.journaldev.xml.Employee;
public class XMLParserSAX {
public static void main(String[] args) {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
try {
SAXParser saxParser = saxParserFactory.newSAXParser();
MyHandler handler = new MyHandler();
saxParser.parse(new File("/Users/pankaj/employees.xml"), handler);
//Get Employees list
List<Employee> empList = handler.getEmpList();
//print employee information
for(Employee emp : empList)
System.out.println(emp);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
这是上述程序的输出。
Employee:: ID=1 Name=Pankaj Age=29 Gender=Male Role=Java Developer
Employee:: ID=2 Name=Lisa Age=35 Gender=Female Role=CEO
Employee:: ID=3 Name=Tom Age=40 Gender=Male Role=Manager
Employee:: ID=4 Name=Meghna Age=25 Gender=Female Role=Manager
SAXParserFactory
提供工厂方法来获取SAXParser
实例。我们将 File 对象与 MyHandler 实例一起传递给解析方法以处理回调事件。SAXParser 一开始有点令人困惑,但如果您正在处理大型 XML 文档,它提供了一种比 DOM Parser 更有效的读取 XML 的方法。这就是 Java 中的 SAX Parser 的全部内容。
您可以从我们的GitHub 存储库下载该项目。