原文: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 文件。

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.codehaus.mojo</groupId>
  5. <artifactId>exec-maven-plugin</artifactId>
  6. <version>1.6.0</version>
  7. <configuration>
  8. <mainClass>com.zetcode.JavaReadXmlSaxEx</mainClass>
  9. </configuration>
  10. </plugin>
  11. </plugins>
  12. </build>

我们使用exec-maven-plugin从 Maven 执行 Java 主类。

users.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <users>
  3. <user id="1">
  4. <firstname>Peter</firstname>
  5. <lastname>Brown</lastname>
  6. <occupation>programmer</occupation>
  7. </user>
  8. <user id="2">
  9. <firstname>Martin</firstname>
  10. <lastname>Smith</lastname>
  11. <occupation>accountant</occupation>
  12. </user>
  13. <user id="3">
  14. <firstname>Lucy</firstname>
  15. <lastname>Gordon</lastname>
  16. <occupation>teacher</occupation>
  17. </user>
  18. </users>

我们将阅读此 XML 文件。

User.java

  1. package com.zetcode;
  2. public class User {
  3. int id;
  4. private String firstName;
  5. private String lastName;
  6. private String occupation;
  7. public User() {
  8. }
  9. public int getId() {
  10. return id;
  11. }
  12. public void setId(int id) {
  13. this.id = id;
  14. }
  15. public String getFirstName() {
  16. return firstName;
  17. }
  18. public void setFirstName(String firstName) {
  19. this.firstName = firstName;
  20. }
  21. public String getLastName() {
  22. return lastName;
  23. }
  24. public void setLastName(String lastName) {
  25. this.lastName = lastName;
  26. }
  27. public String getOccupation() {
  28. return occupation;
  29. }
  30. public void setOccupation(String occupation) {
  31. this.occupation = occupation;
  32. }
  33. @Override
  34. public String toString() {
  35. StringBuilder builder = new StringBuilder();
  36. builder.append("User{").append("id=").append(id)
  37. .append(", firstName=").append(firstName)
  38. .append(", lastName=").append(lastName)
  39. .append(", occupation=").append(occupation).append("}");
  40. return builder.toString();
  41. }
  42. }

这是用户 bean。 它将保存来自 XML 节点的数据。

MyRunner.java

  1. package com.zetcode;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.nio.file.Paths;
  5. import java.util.List;
  6. import java.util.logging.Level;
  7. import java.util.logging.Logger;
  8. import javax.xml.parsers.ParserConfigurationException;
  9. import javax.xml.parsers.SAXParser;
  10. import javax.xml.parsers.SAXParserFactory;
  11. import org.xml.sax.SAXException;
  12. public class MyRunner {
  13. private SAXParser createSaxParser() {
  14. SAXParser saxParser = null;
  15. try {
  16. SAXParserFactory factory = SAXParserFactory.newInstance();
  17. saxParser = factory.newSAXParser();
  18. return saxParser;
  19. } catch (ParserConfigurationException | SAXException ex) {
  20. Logger lgr = Logger.getLogger(MyRunner.class.getName());
  21. lgr.log(Level.SEVERE, ex.getMessage(), ex);
  22. }
  23. return saxParser;
  24. }
  25. public List<User> parseUsers() {
  26. MyHandler handler = new MyHandler();
  27. String fileName = "src/main/resources/users.xml";
  28. File xmlDocument = Paths.get(fileName).toFile();
  29. try {
  30. SAXParser parser = createSaxParser();
  31. parser.parse(xmlDocument, handler);
  32. } catch (SAXException | IOException ex) {
  33. Logger lgr = Logger.getLogger(MyRunner.class.getName());
  34. lgr.log(Level.SEVERE, ex.getMessage(), ex);
  35. }
  36. return handler.getUsers();
  37. }
  38. }

MyRunner创建一个 SAX 解析器并启动解析。 parseUsers返回User对象列表中的解析数据。

  1. SAXParserFactory factory = SAXParserFactory.newInstance();
  2. saxParser = factory.newSAXParser();

SAXParserFactory获得SAXParser

  1. SAXParser parser = createSaxParser();
  2. parser.parse(xmlDocument, handler);

我们使用parse()方法解析文档。 方法的第二个参数是处理器对象,其中包含事件处理器。

MyHandler.java

  1. package com.zetcode;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.xml.sax.Attributes;
  5. import org.xml.sax.SAXException;
  6. import org.xml.sax.helpers.DefaultHandler;
  7. public class MyHandler extends DefaultHandler {
  8. private List<User> users = new ArrayList<>();
  9. private User user;
  10. private boolean bfn = false;
  11. private boolean bln = false;
  12. private boolean boc = false;
  13. @Override
  14. public void startElement(String uri, String localName,
  15. String qName, Attributes attributes) throws SAXException {
  16. if ("user".equals(qName)) {
  17. user = new User();
  18. int id = Integer.valueOf(attributes.getValue("id"));
  19. user.setId(id);
  20. }
  21. switch (qName) {
  22. case "firstname":
  23. bfn = true;
  24. break;
  25. case "lastname":
  26. bln = true;
  27. break;
  28. case "occupation":
  29. boc = true;
  30. break;
  31. }
  32. }
  33. @Override
  34. public void characters(char[] ch, int start, int length) throws SAXException {
  35. if (bfn) {
  36. user.setFirstName(new String(ch, start, length));
  37. bfn = false;
  38. }
  39. if (bln) {
  40. user.setLastName(new String(ch, start, length));
  41. bln = false;
  42. }
  43. if (boc) {
  44. user.setOccupation(new String(ch, start, length));
  45. boc = false;
  46. }
  47. }
  48. @Override
  49. public void endElement(String uri, String localName,
  50. String qName) throws SAXException {
  51. if ("user".equals(qName)) {
  52. users.add(user);
  53. }
  54. }
  55. public List<User> getUsers() {
  56. return users;
  57. }
  58. }

MyHandler类中,我们具有事件处理器的实现。

  1. public class MyHandler extends DefaultHandler {

处理器类必须从具有事件方法的DefaultHandler扩展。

  1. @Override
  2. public void startElement(String uri, String localName,
  3. String qName, Attributes attributes) throws SAXException {
  4. if ("user".equals(qName)) {
  5. user = new User();
  6. int id = Integer.valueOf(attributes.getValue("id"));
  7. user.setId(id);
  8. }
  9. switch (qName) {
  10. case "firstname":
  11. bfn = true;
  12. break;
  13. case "lastname":
  14. bln = true;
  15. break;
  16. case "occupation":
  17. boc = true;
  18. break;
  19. }
  20. }

当解析器开始解析新元素时,将调用startElement()方法。 如果元素为<user>,我们将创建一个新用户。 对于其他类型的元素,我们设置布尔值。

  1. @Override
  2. public void characters(char[] ch, int start, int length) throws SAXException {
  3. if (bfn) {
  4. user.setFirstName(new String(ch, start, length));
  5. bfn = false;
  6. }
  7. if (bln) {
  8. user.setLastName(new String(ch, start, length));
  9. bln = false;
  10. }
  11. if (boc) {
  12. user.setOccupation(new String(ch, start, length));
  13. boc = false;
  14. }
  15. }

当解析器在元素内部遇到文本时,将调用characters()方法。 根据布尔变量,我们设置用户属性。

  1. @Override
  2. public void endElement(String uri, String localName,
  3. String qName) throws SAXException {
  4. if ("user".equals(qName)) {
  5. users.add(user);
  6. }
  7. }

<user>元素的末尾,我们将用户对象添加到用户列表中。

JavaReadXmlSaxEx.java

  1. package com.zetcode;
  2. import java.util.List;
  3. public class JavaReadXmlSaxEx {
  4. public static void main(String[] args) {
  5. MyRunner runner = new MyRunner();
  6. List<User> lines = runner.parseUsers();
  7. lines.forEach(System.out::println);
  8. }
  9. }

JavaReadXmlSaxEx启动应用。 它将解析任务委托给MyRunner。 最后,检索到的数据将打印到控制台。

  1. $ mvn exec:java -q
  2. User{id=1, firstName=Peter, lastName=Brown, occupation=programmer}
  3. User{id=2, firstName=Martin, lastName=Smith, occupation=accountant}
  4. User{id=3, firstName=Lucy, lastName=Gordon, occupation=teacher}

这是示例的输出。

Java SAX 验证示例

以下示例使用 XSD 语言来验证 XML 文件。 XSD(XML 架构定义)是所有 XML 文档和数据的当前标准架构语言。 (还有其他替代的模式语言,例如 DTD 和 RELAX NG。)XSD 是 XML 文档必须遵循的一组规则,以便根据该模式被视为有效。

users.xsd

  1. <?xml version="1.0"?>
  2. <xs:schema version="1.0"
  3. xmlns:xs="http://www.w3.org/2001/XMLSchema"
  4. elementFormDefault="qualified">
  5. <xs:element name="users">
  6. <xs:complexType>
  7. <xs:sequence>
  8. <xs:element name="user" maxOccurs="unbounded" minOccurs="0">
  9. <xs:complexType>
  10. <xs:sequence>
  11. <xs:element type="xs:string" name="firstname"/>
  12. <xs:element type="xs:string" name="lastname"/>
  13. <xs:element type="xs:string" name="occupation"/>
  14. </xs:sequence>
  15. <xs:attribute name="id" type="xs:int" use="required"/>
  16. </xs:complexType>
  17. </xs:element>
  18. </xs:sequence>
  19. </xs:complexType>
  20. </xs:element>
  21. </xs:schema>

这是用于验证用户的 XSD 文件。 例如,它声明<user>元素必须在<users>元素之内,或者<user>id属性必须是且是整数,并且是强制性的。

JavaXmlSchemaValidationEx.java

  1. package com.zetcode;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.Reader;
  5. import java.nio.file.Files;
  6. import java.nio.file.Path;
  7. import java.nio.file.Paths;
  8. import java.util.logging.Level;
  9. import java.util.logging.Logger;
  10. import javax.xml.XMLConstants;
  11. import javax.xml.transform.sax.SAXSource;
  12. import javax.xml.validation.Schema;
  13. import javax.xml.validation.SchemaFactory;
  14. import javax.xml.validation.Validator;
  15. import org.xml.sax.InputSource;
  16. import org.xml.sax.SAXException;
  17. public class JavaXmlSchemaValidationEx {
  18. public static void main(String[] args) {
  19. File xsdFile = new File("src/main/resources/users.xsd");
  20. try {
  21. Path xmlPath = Paths.get("src/main/resources/users.xml");
  22. Reader reader = Files.newBufferedReader(xmlPath);
  23. String schemaLang = XMLConstants.W3C_XML_SCHEMA_NS_URI;
  24. SchemaFactory factory = SchemaFactory.newInstance(schemaLang);
  25. Schema schema = factory.newSchema(xsdFile);
  26. Validator validator = schema.newValidator();
  27. SAXSource source = new SAXSource(new InputSource(reader));
  28. validator.validate(source);
  29. System.out.println("The document was validated OK");
  30. } catch (SAXException ex) {
  31. Logger lgr = Logger.getLogger(JavaXmlSchemaValidationEx.class.getName());
  32. lgr.log(Level.SEVERE, "The document failed to validate");
  33. lgr.log(Level.SEVERE, ex.getMessage(), ex);
  34. } catch (IOException ex) {
  35. Logger lgr = Logger.getLogger(JavaXmlSchemaValidationEx.class.getName());
  36. lgr.log(Level.SEVERE, ex.getMessage(), ex);
  37. }
  38. }
  39. }

该示例使用users.xsd模式来验证users.xml文件。

  1. String schemaLang = XMLConstants.W3C_XML_SCHEMA_NS_URI;
  2. SchemaFactory factory = SchemaFactory.newInstance(schemaLang);
  3. Schema schema = factory.newSchema(xsdFile);

使用SchemaFactory,我们为我们的模式定义选择 W3C XML 模式。 换句话说,我们的自定义架构定义还必须遵守某些规则。

  1. Validator validator = schema.newValidator();

从架构生成一个新的验证器。

  1. SAXSource source = new SAXSource(new InputSource(reader));
  2. validator.validate(source);

我们根据提供的模式验证 XML 文档。

  1. } catch (SAXException ex) {
  2. Logger lgr = Logger.getLogger(JavaXmlSchemaValidationEx.class.getName());
  3. lgr.log(Level.SEVERE, "The document failed to validate");
  4. lgr.log(Level.SEVERE, ex.getMessage(), ex);
  5. }

默认情况下,如果文档无效,则抛出SAXException

在本教程中,我们已使用 Java SAX 阅读并验证了 XML 文档。 您可能也对相关教程感兴趣: Java DOM 教程Java JAXB 教程Java JSON 处理教程提供 XML 的 Java ServletJava 教程