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;
    }

    @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

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;

    @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类中,我们具有事件处理程序的实现。

public class MyHandler extends DefaultHandler {

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

@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()方法。 如果元素为&lt;user&gt;,我们将创建一个新用户。 对于其他类型的元素,我们设置布尔值。

@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()方法。 根据布尔变量,我们设置用户属性。

@Override
public void endElement(String uri, String localName,
        String qName) throws SAXException {

    if ("user".equals(qName)) {
        users.add(user);
    }
}

&lt;user&gt;元素的末尾,我们将用户对象添加到用户列表中。

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 -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

<?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 文件。 例如,它声明&lt;user&gt;元素必须在&lt;users&gt;元素之内,或者&lt;user&gt;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

赞(1)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 教程