SAX и DOM парсинг в Java - примеры и различия подходов.
<test-object> <items type="available browsers"> <item> Firefox </item> <item> Opera </item> <item> IE </item> <item> Chrome </item> </items> <use-browser version="12"> Opera </use-browser> </test-object>
Для того, чтобы использовать SAX парсер, нужно определить класс, расширяющий DefaultHandler и переопределить некоторые из его методов. Именно этот класс и определяет формат выходных данных:
package test; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class TestSAXHandler extends DefaultHandler { private StringBuffer result; public TestSAXHandler(){ result = new StringBuffer(); } @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { //имя тега result.append("Element name = '"+ qName+"'\n"); //атрибуты тега for (int i = 0; i < atts.getLength(); i++){ result.append("Attribute name = '" + atts.getQName(i) + "'; Attribute value = '" + atts.getValue(i)+"'\n"); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String value = ""; //содержимое тега for (int i = start; i < length; i++){ value += ch[i]; } if (value.length() != 0) result.append("Element content = '" + value.trim() + "'\n"); } @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { //закрытие тега result.append("Element closed, name = '" + qName + "'\n"); } public String getResult(){ return result.toString(); } }
SAX парсер работает в данном случае так - когда в исходном документе встречается открывающий тег, вызывается метод startElement с соответствующими параметрами. При чтении содержимого тега вызывается characters. При закрытии тега - endElement. Таким образом документ и разбирается без предварительной его загрузки в память. Для использования DOM парсера просто создадим класс, работающий с объектом типа Document и определяющим формат выходных данных. Здесь никаких событий нет, есть уже загруженный объект типа Document, который является представлением исходных данных.
package test; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class DomParser { public String parse(Document input) { //передаем корневой элемент XML документа return parseNode(input.getDocumentElement()); } private String parseNode(Node node) { //если текущий элемент - текстовое содержимое тега if (node.getNodeName().equals("#text")) return ""; StringBuffer result = new StringBuffer(); //имя тега result.append("Element name = '" + node.getNodeName() + "'\n"); //атрибуты тега NamedNodeMap nodeMap = node.getAttributes(); if (nodeMap != null) { for (int i = 0; i < nodeMap.getLength(); i ++){ result.append("Attribute name = '" + nodeMap.item(i).getNodeName() + "'; Attribute value = '" + nodeMap.item(i).getNodeValue() + "'\n"); } } //содержимое элемента if (getElementContent(node) != null && !(getElementContent(node).equals(""))) result.append("Element content = '" + getElementContent(node)+"'\n"); NodeList nodeList = node.getChildNodes(); //рекурсивно вызываем метод для каждого из подэлементов в //переданном элементе for (int i = 0; i < nodeList.getLength(); i++){ result.append(parseNode(nodeList.item(i))); } //закрытие тега result.append("Element closed, name = '" + node.getNodeName() + "'\n"); return result.toString(); } private String getElementContent(Node node) { Node contentNode = node.getFirstChild(); if (contentNode != null) if (contentNode.getNodeName().equals("#text")) { String value = contentNode.getNodeValue(); if (value != null) return value.trim(); } return null; } }
Теперь осталось только загрузить исходные данные и использовать реализованные парсеры:
package test; import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.w3c.dom.Document; public class Main { private final static String PATH = "C:\\Users\\alex\\test.xml"; public static void main(String args[]){ //Входной файл, содержащий XML документ File input = new File(PATH); //SAX парсер try { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); TestSAXHandler handler = new TestSAXHandler(); parser.parse(input, handler); System.out.println("SAX parser result:\n" + handler.getResult()); } catch (Exception e) { e.printStackTrace(); } //DOM парсер try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory .newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(input); doc.getDocumentElement().normalize(); DomParser domParser = new DomParser(); System.out.println("DOM parser result:\n" + domParser.parse(doc)); } catch (Exception e) { e.printStackTrace(); } } }
Результат парсинга для первого и второго вариантов выглядит аналогично:
Element name = 'test-object' Element name = 'items' Attribute name = 'type'; Attribute value = 'available browsers' Element name = 'item' Element content = 'Firefox' Element closed, name = 'item' Element name = 'item' Element content = 'Opera' Element closed, name = 'item' Element name = 'item' Element content = 'IE' Element closed, name = 'item' Element name = 'item' Element content = 'Chrome' Element closed, name = 'item' Element closed, name = 'items' Element name = 'use-browser' Attribute name = 'version'; Attribute value = '12' Element content = 'Opera' Element closed, name = 'use-browser' Element closed, name = 'test-object'
Какой парсер лучше использовать в вашем случае - SAX или DOM, можно решить по типу исходных данных. Если исходный документ большой по объему и вложенность элементов невысока - скорее всего SAX, при этом подходе разбор исходных данных происходит несколько быстрее и используется меньше памяти. Если нужно преобразовать сложную структуру данных - наверное удобнее и проще будет работать с DOM.
Теги: programming java
comments powered by Disqus