企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# Java SAX 教程 原文: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 文件。 ```java <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` ```java <?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` ```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; } @Override public 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` ```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`对象列表中的解析数据。 ```java SAXParserFactory factory = SAXParserFactory.newInstance(); saxParser = factory.newSAXParser(); ``` 从`SAXParserFactory`获得`SAXParser`。 ```java SAXParser parser = createSaxParser(); parser.parse(xmlDocument, handler); ``` 我们使用`parse()`方法解析文档。 方法的第二个参数是处理器对象,其中包含事件处理器。 `MyHandler.java` ```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; @Override public 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; } } @Override public 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; } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("user".equals(qName)) { users.add(user); } } public List<User> getUsers() { return users; } } ``` 在`MyHandler`类中,我们具有事件处理器的实现。 ```java public class MyHandler extends DefaultHandler { ``` 处理器类必须从具有事件方法的`DefaultHandler`扩展。 ```java @Override public 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>`,我们将创建一个新用户。 对于其他类型的元素,我们设置布尔值。 ```java @Override public 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()`方法。 根据布尔变量,我们设置用户属性。 ```java @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("user".equals(qName)) { users.add(user); } } ``` 在`<user>`元素的末尾,我们将用户对象添加到用户列表中。 `JavaReadXmlSaxEx.java` ```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`。 最后,检索到的数据将打印到控制台。 ```java $ mvn exec:java -q User{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` ```java <?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` ```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`文件。 ```java String schemaLang = XMLConstants.W3C_XML_SCHEMA_NS_URI; SchemaFactory factory = SchemaFactory.newInstance(schemaLang); Schema schema = factory.newSchema(xsdFile); ``` 使用`SchemaFactory`,我们为我们的模式定义选择 W3C XML 模式。 换句话说,我们的自定义架构定义还必须遵守某些规则。 ```java Validator validator = schema.newValidator(); ``` 从架构生成一个新的验证器。 ```java SAXSource source = new SAXSource(new InputSource(reader)); validator.validate(source); ``` 我们根据提供的模式验证 XML 文档。 ```java } 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/dom/), [Java JAXB 教程](/java/jaxb/), [Java JSON 处理教程](/java/jsonp/),[提供 XML 的 Java Servlet](/articles/javaservletservexml/) 和 [Java 教程](/lang/java/)。