Java SAX解析示例

时间:2020-01-09 10:36:30  来源:igfitidea点击:

在本文中,我将向我们展示一个示例,该示例说明如何使用SAX解析器解析XML文件,以及如何从解析的XML构建对象图。

这是我要解析的XML文档:

<driverVehicleInfo>
    <vehicle>
        <vehicleId>1</vehicleId>
        <name>Limousine</name>
    </vehicle>
    <vehicle>
        <vehicleId>2</vehicleId>
        <name>Aston Martin</name>
    </vehicle>
    <vehicle>
        <vehicleId>3</vehicleId>
        <name>Bus</name>
    </vehicle>

    <driver>
        <driverId>1</driverId>
        <firstName>John</firstName>
        <lastName>Doe</lastName>
        <vehicleId>1</vehicleId>
        <vehicleId>2</vehicleId>
    </driver>
    <driver>
        <driverId>2</driverId>
        <name>Joe Blocks</name>
        <vehicleId>3</vehicleId>
    </driver>
</driverVehicleInfo>

我想将这个XML结构解析为链接到"车辆"对象的"驱动程序"对象的对象结构。这是这两个类的定义。为了简化代码,我跳过了getter和setter方法。 toString()方法不是必需的。它们仅用于更轻松地打印示例中的结果。

public class Driver {
    public String driverId = null;
    public String name     = null;

    public List<Vehicle> vehicles = new ArrayList<Vehicle>();

    public String toString() {
        return this.driverId + " : " +
               this.name     + " : " +
               this.vehicles;
    }

}
public class Vehicle {
    public String vehicleId = null;
    public String name      = null;

    public String toString() {
        return  this.vehicleId + " : " +
                this.name;
    }
}

这是执行解析的DefaultHandler子类。请注意,它是如何使用两个堆栈来保持对XML元素的分析,并创建" Driver"和" Vehicle"对象。

还要注意,如果<vehicle>元素是在XML文件中的最后而不是第一个列出的,则此处理程序将无法工作。原因是,当处理<driver>元素时,他们希望已经填写了vehiclesMap。如果在&lt;driver>元素之后列出了&lt;vehicle>元素,则在处理&lt;driver>元素时,vehiclesMap将为空。

我将把它作为练习,让我们了解其中发生的事情。它并不完全容易理解这一事实本身就是一个信息。 SAX可能很快,但是我们使用它编写的代码并不总是看起来太优雅。

package xml.sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.util.*;

/**

 */
public class SaxHandler extends DefaultHandler {

    public List<Driver>         drivers  = new ArrayList<Driver>();
    public Map<String, Vehicle> vehicles = new HashMap<String, Vehicle>();

    private Stack<String> elementStack = new Stack<String>();
    private Stack<Object> objectStack  = new Stack<Object>();

    public void startElement(String uri, String localName,
        String qName, Attributes attributes) throws SAXException {

        this.elementStack.push(qName);

        if("driver".equals(qName)){
            Driver driver = new Driver();
            this.objectStack.push(driver);
            this.drivers.add(driver);
        } else if("vehicle".equals(qName)){
            this.objectStack.push(new Vehicle());
        }
    }

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

        this.elementStack.pop();

        if("vehicle".equals(qName) || "driver".equals(qName)){
            Object object = this.objectStack .pop();
            if("vehicle".equals(qName)){
                Vehicle vehicle = (Vehicle) object;
                this.vehicles.put(vehicle.vehicleId, vehicle);
            }
        }
    }

    public void characters(char ch[], int start, int length)
        throws SAXException {

        String value = new String(ch, start, length).trim();
        if(value.length() == 0) return; // ignore white space

        if("driverId".equals(currentElement())){
            Driver driver = (Driver) this.objectStack.peek();
            driver.driverId = (driver.driverId != null ?
                               driver.driverId  : "") + value;
        } else if("name"  .equals(currentElement()) &&
                  "driver".equals(currentElementParent())){

            Driver driver = (Driver) this.objectStack.peek();
            driver.name = (driver.name != null ?
                                driver.name  : "") + value;

        } else if("vehicleId".equals(currentElement()) &&
                  "driver"   .equals(currentElementParent())){

            Driver driver = (Driver) this.objectStack.peek();
            Vehicle vehicle = this.vehicles.get(value);
            if(vehicle != null) driver.vehicles.add(vehicle);

        } else if("vehicleId".equals(currentElement()) &&
                  "vehicle"  .equals(currentElementParent())){

            Vehicle vehicle   = (Vehicle) this.objectStack.peek();
            vehicle.vehicleId = (vehicle.vehicleId != null ?
                                    vehicle.vehicleId  : "")  + value;

        } else if("name"   .equals(currentElement()) &&
                  "vehicle".equals(currentElementParent())){

            Vehicle vehicle = (Vehicle) this.objectStack.peek();
            vehicle.name = (vehicle.name != null ? vehicle.name  : "")
                               + value;
        }
    }

    private String currentElement() {
        return this.elementStack.peek();
    }

    private String currentElementParent() {
        if(this.elementStack.size() < 2) return null;
        return this.elementStack.get(this.elementStack.size()-2);
    }

}

这是运行示例的代码:

public class SaxParserExample {

    public static void main (String argv []) {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            InputStream    xmlInput  =
                new FileInputStream("data\sax-example.xml");

            SAXParser      saxParser = factory.newSAXParser();
            SaxHandler handler   = new SaxHandler();
            saxParser.parse(xmlInput, handler);

            for(Driver driver : handler.drivers){
                System.out.println(driver);
            }
        } catch (Throwable err) {
            err.printStackTrace ();
        }
    }
}

这是使用给定的XML文件,处理程序和运行程序示例产生的输出:

1 : John Doe : [1 : Limousine, 2 : Aston Martin]
2 : Joe Blocks : [3 : Bus]