Java SAX解析器:高效XML数据处理与应用指南
这是文章《Java SAX 解析器示例》的第1部分(共1部分)。
内容片段: SAX解析器是Java中提供API来解析XML文档的工具。SAX解析器和DOM解析器不同的地方在于它不会将整个XML文档加载到内存中,而是按顺序读取XML文档。
SAX 解析器
javax.xml.parsers.SAXParser
提供使用事件处理程序解析XML文档的方法。该类实现了XMLReader
接口,并提供了不同版本的parse()
方法来从File
、InputStream
、SAX InputSource
和String URI
中读取XML文档。实际的解析由Handler
类执行。我们需要创建自己的处理程序类来解析XML文档。我们需要实现org.xml.sax.ContentHandler
接口来创建我们自己的处理程序类。该接口包含在事件发生时接收通知的回调方法。例如StartDocument
、EndDocument
、StartElement
、EndElement
、CharacterData
等。org.xml.sax.helpers.DefaultHandler
提供了ContentHandler
接口的默认实现,我们可以通过扩展该类来创建自己的处理程序。建议扩展该类,因为我们可能只需要实现其中的几个方法。通过扩展该类,我们的代码将更加清晰和可维护。
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
属性和年龄、姓名、性别和职位字段。我们将使用SAX解析器来解析这个XML,并创建一个员工对象的列表。这里是代表XML中员工元素的员工对象。
package com.Olivia.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;
}
}
让我们创建一个扩展DefaultHandler
类的自定义SAX解析器处理程序类。
package com.Olivia.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.Olivia.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
字段。当SAXParser在元素内找到字符数据时,会调用characters()
方法。请注意,SAX解析器可能会将数据分成多个块,并多次调用characters()
方法(请阅读ContentHandler
类characters()
方法的文档)。这就是为什么我们使用StringBuilder
来保持这些数据,并使用append()
方法。endElement()
是使用StringBuilder
数据设置Employee
对象属性并在找到Employee
结束元素标签时将Employee
对象添加到列表中的位置。下面是使用MyHandler
解析上述XML到Employee
对象列表的测试程序。
package com.Olivia.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.Olivia.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/scdev/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
对象传递给parse
方法,并与MyHandler
实例一起处理回调事件。SAXParser在开始时可能有点困惑,但如果你正在处理一个大型XML文档,它提供了比DOM解析器更高效的读取XML的方式。以上就是关于Java中的SAX解析器的全部内容。
您可以从我们的GitHub存储库下载该项目。