Java SAX解析器示例
Java中的SAX Parser提供了用于解析XML文档的API。
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>hyman</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文件存储在文件系统中的某个位置,通过查看它,我们可以得出结论,该文件包含Employee列表。
每个员工都有" id"属性,并字段"年龄","姓名","性别"和"角色"。
我们将使用SAX解析器来解析此XML并创建Employee对象的列表。
这是代表XML中的Employee元素的Employee对象。
package com.theitroad.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.theitroad.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.theitroad.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仅使用getter方法将" Employee"对象的列表作为字段包含在内。
在事件处理程序方法中添加了" Employee"对象。
另外,我们还有一个Employee字段,它将用于创建Employee对象,并且一旦设置了所有字段,就将其添加到employee列表中。
SAX解析器方法重写
覆盖的重要方法是startElement()
,endElement()
和characters()
。
当发现任何起始元素时,SAXParser
开始解析文档,调用startElement()
方法。
我们重写此方法来设置将用于标识元素的布尔变量。
每当找到Employee start元素时,我们也使用此方法创建一个新的Employee对象。
检查此处如何读取id属性,以设置Employee Objectid
字段。
SAXParser在元素内部发现字符数据时,将调用" characters()"方法。
请注意,SAX解析器可能会将数据分为多个块,并多次调用characters()
方法(请参阅ContentHandler类character()方法文档)。
这就是为什么我们使用StringBuilder通过append()方法保留此数据的原因。
" endElement()"是我们使用StringBuilder数据设置员工对象属性并将Employee对象添加到列表的地方,只要我们找到Employee end element标签即可。
下面是使用MyHandler解析XML到Employee对象列表的测试程序。
package com.theitroad.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.theitroad.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/hyman/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=hyman 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实例一起传递给parse方法,以处理回调事件。
首先,SAXParser有点令人困惑,但是如果您正在处理大型XML文档,则它提供了比DOM Parser更有效的XML读取方式。
Java的SAX解析器就这些了。