Java SAX — пример синтаксического анализа

Рассмотрим, как проанализировать XML-файл с использованием SAX-анализатора и построить граф объектов из проанализированного XML-файла.

Вот XML-документ, который будем анализировать:

    
        1
        Limousine
    
    
        2
        Aston Martin
    
    
        3
        Bus
    

    
        1
        John
        Doe
        1
        2
    
    
        2
        Joe Blocks
        3
    

Эту XML-структуру разберем в объектную структуру объектов Driver, связанных с объектами Vehicle. Вот определение этих двух классов. Пропущены методы получения и установки только для того, чтобы сократить код. Методы toString() не нужны. Они используются только для облегчения распечатки результатов в примере.

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

    public List vehicles = new ArrayList();

    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.

Обратите также внимание, что если элементы были перечислены последними в файле XML вместо первого, этот обработчик не работал бы.

Причина в том, что когда элементы обрабатываются, они ожидают, что автомобили уже заполнены. Если элементы vehicle были перечислены после элементов driver, vehicles Map будет пустой, когда driver  элементы были обработаны.

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         drivers  = new ArrayList();
    public Map vehicles = new HashMap();

    private Stack elementStack = new Stack();
    private Stack objectStack  = new Stack();    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]

Оцените статью