Java SAX 解析器示例

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存储库下载该项目。

参考:SAX解析器,默认处理程序。

发表回复 0

Your email address will not be published. Required fields are marked *