原文:http://zetcode.com/java/sax/
Java SAX 教程展示了如何使用 Java SAX API 来读取和验证 XML 文档。
SAX
SAX(XML 的简单 API)是事件驱动的算法,用于解析 XML 文档。 SAX 是文档对象模型(DOM)的替代方法。 在 DOM 读取整个文档以对 XML 进行操作的地方,SAX 解析器逐个节点读取 XML,发出解析事件,同时逐步遍历输入流。 SAX 独立于状态处理文档(元素的处理不依赖于之前的元素)。 SAX 解析器是只读的。
SAX 解析器更快并且需要更少的内存。 另一方面,DOM 更易于使用,并且有些任务(例如,排序元素,重新排列元素或查找元素)使用 DOM 更快。
SADK 解析器是 JDK 附带的,因此不需要下载依赖项。
Java SAX 解析示例
在下面的示例中,我们使用 SAX 解析器读取 XML 文件。
<build><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>exec-maven-plugin</artifactId><version>1.6.0</version><configuration><mainClass>com.zetcode.JavaReadXmlSaxEx</mainClass></configuration></plugin></plugins></build>
我们使用exec-maven-plugin从 Maven 执行 Java 主类。
users.xml
<?xml version="1.0" encoding="UTF-8"?><users><user id="1"><firstname>Peter</firstname><lastname>Brown</lastname><occupation>programmer</occupation></user><user id="2"><firstname>Martin</firstname><lastname>Smith</lastname><occupation>accountant</occupation></user><user id="3"><firstname>Lucy</firstname><lastname>Gordon</lastname><occupation>teacher</occupation></user></users>
我们将阅读此 XML 文件。
User.java
package com.zetcode;public class User {int id;private String firstName;private String lastName;private String occupation;public User() {}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getOccupation() {return occupation;}public void setOccupation(String occupation) {this.occupation = occupation;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("User{").append("id=").append(id).append(", firstName=").append(firstName).append(", lastName=").append(lastName).append(", occupation=").append(occupation).append("}");return builder.toString();}}
这是用户 bean。 它将保存来自 XML 节点的数据。
MyRunner.java
package com.zetcode;import java.io.File;import java.io.IOException;import java.nio.file.Paths;import java.util.List;import java.util.logging.Level;import java.util.logging.Logger;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.SAXException;public class MyRunner {private SAXParser createSaxParser() {SAXParser saxParser = null;try {SAXParserFactory factory = SAXParserFactory.newInstance();saxParser = factory.newSAXParser();return saxParser;} catch (ParserConfigurationException | SAXException ex) {Logger lgr = Logger.getLogger(MyRunner.class.getName());lgr.log(Level.SEVERE, ex.getMessage(), ex);}return saxParser;}public List<User> parseUsers() {MyHandler handler = new MyHandler();String fileName = "src/main/resources/users.xml";File xmlDocument = Paths.get(fileName).toFile();try {SAXParser parser = createSaxParser();parser.parse(xmlDocument, handler);} catch (SAXException | IOException ex) {Logger lgr = Logger.getLogger(MyRunner.class.getName());lgr.log(Level.SEVERE, ex.getMessage(), ex);}return handler.getUsers();}}
MyRunner创建一个 SAX 解析器并启动解析。 parseUsers返回User对象列表中的解析数据。
SAXParserFactory factory = SAXParserFactory.newInstance();saxParser = factory.newSAXParser();
从SAXParserFactory获得SAXParser。
SAXParser parser = createSaxParser();parser.parse(xmlDocument, handler);
我们使用parse()方法解析文档。 方法的第二个参数是处理器对象,其中包含事件处理器。
MyHandler.java
package com.zetcode;import java.util.ArrayList;import java.util.List;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;public class MyHandler extends DefaultHandler {private List<User> users = new ArrayList<>();private User user;private boolean bfn = false;private boolean bln = false;private boolean boc = false;@Overridepublic void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {if ("user".equals(qName)) {user = new User();int id = Integer.valueOf(attributes.getValue("id"));user.setId(id);}switch (qName) {case "firstname":bfn = true;break;case "lastname":bln = true;break;case "occupation":boc = true;break;}}@Overridepublic void characters(char[] ch, int start, int length) throws SAXException {if (bfn) {user.setFirstName(new String(ch, start, length));bfn = false;}if (bln) {user.setLastName(new String(ch, start, length));bln = false;}if (boc) {user.setOccupation(new String(ch, start, length));boc = false;}}@Overridepublic void endElement(String uri, String localName,String qName) throws SAXException {if ("user".equals(qName)) {users.add(user);}}public List<User> getUsers() {return users;}}
在MyHandler类中,我们具有事件处理器的实现。
public class MyHandler extends DefaultHandler {
处理器类必须从具有事件方法的DefaultHandler扩展。
@Overridepublic void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {if ("user".equals(qName)) {user = new User();int id = Integer.valueOf(attributes.getValue("id"));user.setId(id);}switch (qName) {case "firstname":bfn = true;break;case "lastname":bln = true;break;case "occupation":boc = true;break;}}
当解析器开始解析新元素时,将调用startElement()方法。 如果元素为<user>,我们将创建一个新用户。 对于其他类型的元素,我们设置布尔值。
@Overridepublic void characters(char[] ch, int start, int length) throws SAXException {if (bfn) {user.setFirstName(new String(ch, start, length));bfn = false;}if (bln) {user.setLastName(new String(ch, start, length));bln = false;}if (boc) {user.setOccupation(new String(ch, start, length));boc = false;}}
当解析器在元素内部遇到文本时,将调用characters()方法。 根据布尔变量,我们设置用户属性。
@Overridepublic void endElement(String uri, String localName,String qName) throws SAXException {if ("user".equals(qName)) {users.add(user);}}
在<user>元素的末尾,我们将用户对象添加到用户列表中。
JavaReadXmlSaxEx.java
package com.zetcode;import java.util.List;public class JavaReadXmlSaxEx {public static void main(String[] args) {MyRunner runner = new MyRunner();List<User> lines = runner.parseUsers();lines.forEach(System.out::println);}}
JavaReadXmlSaxEx启动应用。 它将解析任务委托给MyRunner。 最后,检索到的数据将打印到控制台。
$ mvn exec:java -qUser{id=1, firstName=Peter, lastName=Brown, occupation=programmer}User{id=2, firstName=Martin, lastName=Smith, occupation=accountant}User{id=3, firstName=Lucy, lastName=Gordon, occupation=teacher}
这是示例的输出。
Java SAX 验证示例
以下示例使用 XSD 语言来验证 XML 文件。 XSD(XML 架构定义)是所有 XML 文档和数据的当前标准架构语言。 (还有其他替代的模式语言,例如 DTD 和 RELAX NG。)XSD 是 XML 文档必须遵循的一组规则,以便根据该模式被视为有效。
users.xsd
<?xml version="1.0"?><xs:schema version="1.0"xmlns:xs="http://www.w3.org/2001/XMLSchema"elementFormDefault="qualified"><xs:element name="users"><xs:complexType><xs:sequence><xs:element name="user" maxOccurs="unbounded" minOccurs="0"><xs:complexType><xs:sequence><xs:element type="xs:string" name="firstname"/><xs:element type="xs:string" name="lastname"/><xs:element type="xs:string" name="occupation"/></xs:sequence><xs:attribute name="id" type="xs:int" use="required"/></xs:complexType></xs:element></xs:sequence></xs:complexType></xs:element></xs:schema>
这是用于验证用户的 XSD 文件。 例如,它声明<user>元素必须在<users>元素之内,或者<user>的id属性必须是且是整数,并且是强制性的。
JavaXmlSchemaValidationEx.java
package com.zetcode;import java.io.File;import java.io.IOException;import java.io.Reader;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.util.logging.Level;import java.util.logging.Logger;import javax.xml.XMLConstants;import javax.xml.transform.sax.SAXSource;import javax.xml.validation.Schema;import javax.xml.validation.SchemaFactory;import javax.xml.validation.Validator;import org.xml.sax.InputSource;import org.xml.sax.SAXException;public class JavaXmlSchemaValidationEx {public static void main(String[] args) {File xsdFile = new File("src/main/resources/users.xsd");try {Path xmlPath = Paths.get("src/main/resources/users.xml");Reader reader = Files.newBufferedReader(xmlPath);String schemaLang = XMLConstants.W3C_XML_SCHEMA_NS_URI;SchemaFactory factory = SchemaFactory.newInstance(schemaLang);Schema schema = factory.newSchema(xsdFile);Validator validator = schema.newValidator();SAXSource source = new SAXSource(new InputSource(reader));validator.validate(source);System.out.println("The document was validated OK");} catch (SAXException ex) {Logger lgr = Logger.getLogger(JavaXmlSchemaValidationEx.class.getName());lgr.log(Level.SEVERE, "The document failed to validate");lgr.log(Level.SEVERE, ex.getMessage(), ex);} catch (IOException ex) {Logger lgr = Logger.getLogger(JavaXmlSchemaValidationEx.class.getName());lgr.log(Level.SEVERE, ex.getMessage(), ex);}}}
该示例使用users.xsd模式来验证users.xml文件。
String schemaLang = XMLConstants.W3C_XML_SCHEMA_NS_URI;SchemaFactory factory = SchemaFactory.newInstance(schemaLang);Schema schema = factory.newSchema(xsdFile);
使用SchemaFactory,我们为我们的模式定义选择 W3C XML 模式。 换句话说,我们的自定义架构定义还必须遵守某些规则。
Validator validator = schema.newValidator();
从架构生成一个新的验证器。
SAXSource source = new SAXSource(new InputSource(reader));validator.validate(source);
我们根据提供的模式验证 XML 文档。
} catch (SAXException ex) {Logger lgr = Logger.getLogger(JavaXmlSchemaValidationEx.class.getName());lgr.log(Level.SEVERE, "The document failed to validate");lgr.log(Level.SEVERE, ex.getMessage(), ex);}
默认情况下,如果文档无效,则抛出SAXException。
在本教程中,我们已使用 Java SAX 阅读并验证了 XML 文档。 您可能也对相关教程感兴趣: Java DOM 教程, Java JAXB 教程, Java JSON 处理教程,提供 XML 的 Java Servlet 和 Java 教程。
