zoukankan      html  css  js  c++  java
  • XML解析技术

    XML解析技术

    DOM技术:文档对象模型,需要将整个XML加入内存才能解析,占用内存比较多

    SAX技术:一边加载,一边解析,一边释放内存,比较节省内存,基于推模式

    STAX技术:一种至于流的技术,和SAX技术很像,是基于拉模式的

    推模式与拉模式

    推模式就好像服务器主动给你发送消息一样,当使用SAX技术时,xml解析器碰到一个标签就会触发一个事件,而且一旦开始解析就不会停下来,知道所有内容解析完毕,不能人为的控制解析过程。

    拉模式类似客户端发起HTTP请求后服务器才发送内容,使用STAX技术时,会碰到一个标签解析一下然后停止解析,如果还需要解析的话必须人为的启动解析,就好像解析器开启懒人模式一样。

    基于以上技术实现的解析工具有

    JAXP 同时支持DOM SAX STAX三种技术

    DOM4J 支持DOM解析方式

    XML PULL android移动设备内置的xml解析技术, 支持STAX解析方式

    技术选择

    在javaee开发中通常使用DOM技术,编程简单。当xml文档过于大时,优先使用SAX/STAX技术。

    JAXP解析代码

    JAXP(Java API for XML Processing)提供了DOM和SAX的接口,因此可用其对XML文件进行解析。以下面的XML文件为例,说明JAXP的使用方式。

    XML文件

    <?xml version="1.0" encoding="UTF-8"?>
    <books>
        <book>
            <name>adfafd</name>
            <price>123</price>
        </book>
        <book>
            <name>dfadfe</name>
            <price>2321</price>
        </book>
    </books>
    

    DOM解析API

    全局查找

    通过ID查找 getElementById() //无约束的DTD文档不能使用该方法
    通过标签名查找 getElementsByTagName()

    相对节点位置查找
    getChildNodes(): 返回这个节点的所有子节点列表
    getFirstChild(): 返回这个节点的第一个子节点
    getParentNode(): 返回这个节点的父节点对象
    getPreviousSibling(): 返回其前一个兄弟节点
    getNextSibling(): 返回该节点下一个兄弟节点

    DOM读取XML文件

    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.NodeList;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    
    
    public class DOMTest {
        @Test
        public void demo1() throws ParserConfigurationException, SAXException,IOException {
            // 构造工厂
            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
            // 通过工厂获得解析器
            DocumentBuilder builder = builderFactory.newDocumentBuilder();
            // 使用解析器加载xml文档
            Document document = builder.parse("books.xml");
            // 通过标签名获得元素
            NodeList nodeList = document.getElementsByTagName("name");
            for (int i = 0; i < nodeList.getLength(); i++) {
                Element e = (Element) nodeList.item(i);
                // 获取标签名称
                System.out.println(e.getNodeName());
                // 获取<name>标签子节点
                System.out.println(e.getFirstChild().getNodeValue());
                // 获取<name>标签类型
                System.out.println(e.getNodeType());
        	}
    	}
    }
    

    DOM的增加节点操作

    public void DOM2Test() throws ParserConfigurationException, SAXException,
    IOException, TransformerException,
    TransformerConfigurationException {
    	DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        // 通过工厂获得解析器
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        // 使用解析器加载xml文档
        Document document = builder.parse("books.xml");
        // 创建元素节点
        Element time = document.createElement("time");
        // 设置节点包含的文本内容
        time.setTextContent("2015-12-28");
        // 获取欲加入位置
        NodeList nodeList = document.getElementsByTagName("name");
        //将节点<time>加入到<name>下
        nodeList.item(0).appendChild(time);
        // 将新的DOM对象重新写会原文件
        TransformerFactory transformerFactory = TransformerFactory
        .newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource domSource = new DOMSource(document);
        StreamResult streamResult = new StreamResult(new File("books.xml"));
        transformer.transform(domSource, streamResult);
    }
    

    DOM修改节点

    public void DOM2Test() throws ParserConfigurationException, SAXException,
    IOException, TransformerException,TransformerConfigurationException {
    	DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        // 通过工厂获得解析器
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        // 使用解析器加载xml文档
        Document document = builder.parse("books.xml");
        // 获取欲修改位置
        NodeList nodeList = document.getElementsByTagName("name");
        int nodeListLength = nodeList.getLength();
        for (int i = 0; i < nodeListLength; i++) {
            Element e = (Element) nodeList.item(i);
            if (e.getTextContent().equals("java编程思想")) {
                String oldPrice = e.getNextSibling().getTextContent();
                int newPrice = (int) (Integer.parseInt(oldPrice) * 1.5);
                e.getNextSibling().setTextContent(String.valueOf(newPrice));
    		}
    	}
        // 将新的DOM对象重新写会原文件
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource domSource = new DOMSource(document);
        StreamResult streamResult = new StreamResult(new File("books.xml"));
        transformer.transform(domSource, streamResult);
    }
    

    DOM的删除操作

    public void DOM2Test() throws ParserConfigurationException, SAXException,
    IOException, TransformerException,TransformerConfigurationException {
    	DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    	// 通过工厂获得解析器
    	DocumentBuilder builder = builderFactory.newDocumentBuilder();
    	// 使用解析器加载xml文档
    	Document document = builder.parse("books.xml");
    	// 获取欲修改位置
    	NodeList nodeList = document.getElementsByTagName("name");
    	int nodeListLength = nodeList.getLength();
    	for (int i = 0; i < nodeListLength; i++) {
    		Element e = (Element) nodeList.item(i);
    		System.out.println(e.getTextContent());
    		if (e.getTextContent().equals("java编程思想")) {
    			e.getParentNode().removeChild(e);
    		//<name>节点被删除后,<price>节点成为第一个节点,所以要减1
    			i--;
    		}
    	}
    	// 将新的DOM对象重新写会原文件
    	TransformerFactory transformerFactory = TransformerFactory.newInstance();
    	Transformer transformer = transformerFactory.newTransformer();
    	DOMSource domSource = new DOMSource(document);
    	StreamResult streamResult = new StreamResult(new File("books.xml"));
    	transformer.transform(domSource, streamResult);
    	}
    }
    

    SAX

    SAX是基于事件驱动的XML处理方法,当SAX解析器标签的起始标记时会回调starElement()方法,比如遇到了

    标签就会回调该方法,endElement()函数是遇到结束标签时调用该方法。

    SAX测试代码:

    首先需要复写DefaultHandler类

    import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.DefaultHandler;
    
    public class MyHandler extends DefaultHandler {
    	@Override
    	public void startDocument() throws SAXException {
    		System.out.println("start Document...");
    	}
    
    	@Override
    	public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
    		System.out.println(qName);
    		if (qName.equals("book"))
    			//标签的属性以键值对方式存储
    			System.out.println("id属性为:" + attributes.getValue("id"));
    	}		
    
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            String string = new String(ch, start, length);
            System.out.println("start character..." + string);
        }
    
        @Override
        public void endElement(String uri, String localName, String qName)throws SAXException {
            System.out.println("end element..." + qName);
        }
    
        @Override
        public void endDocument() throws SAXException {
            System.out.println("end Document...");
        }
    }
    

    构建解析器进行解析,解析器在进行解析时,会调用Handler中的方法进行处理

    public void SAXTest() throws ParserConfigurationException, SAXException,IOException {
        // 创建解析工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // 创建解析器
        SAXParser saxParser = factory.newSAXParser();
        // 初始化回调函数
        MyHandler handler = new MyHandler();
        //将解析的文档和回调函数一并传入
        saxParser.parse("books.xml", handler);
    }
    

    参考

    STAX

    STAX模式在Android中使用,因此下面的代码只能在Android环境下运行

    STAX测试代码:

    测试文档为上面的books.xml

    @Test
    public void TestPull() throws XmlPullParserException, IOException {
    	// 创建工厂
    	XmlPullParserFactory pullParserFactory = XmlPullParserFactory.newInstance();
    	// 通过工厂获得解析器
    	XmlPullParser pullParser = pullParserFactory.newPullParser();
    	// 将XML文档传入
    	pullParser.setInput(new FileInputStream("books.xml"), "utf-8");
    	// 获取事件类型
    	while (pullParser.getEventType() != XmlPullParser.END_DOCUMENT) {
    		if (pullParser.getEventType() == XmlPullParser.START_TAG) {
    			if (pullParser.getName().equals("name"))
    				System.out.println(pullParser.nextText());
    		}
    		pullParser.next();
    	}
    }
    
    使用XML PULL生成XML文档
    
    public void SerializerTest() throws XmlPullParserException,
    IllegalArgumentException, IllegalStateException,
    FileNotFoundException, IOException {
    	XmlPullParserFactory pullParserFactory = XmlPullParserFactory.newInstance();
    	XmlSerializer serializer = pullParserFactory.newSerializer();
    	// 设置序列化文档
    	serializer.setOutput(new FileOutputStream("books_blank.xml"), "utf-8");
    	serializer.startDocument("utf-8", true);
    	serializer.startTag(null, "admin");
    	serializer.startTag(null, "username");
    	serializer.text("root");
    	serializer.endTag(null, "username");
    	serializer.endTag(null, "admin");
    	serializer.endDocument();
    }
    

    总结

    由于DOM是将整个XML装载进内存,因此可以直接在内存直接操作XML文件。由于SAX和STAX技术对XML解析一部分后直接释放内存,再将下一部分装入内存,所以我们无法使用SAX或STAX来直接修改XML文档,可以先用SAX解析后转换成多个对象(用ArrayList存储),然后这些对象进行修改,在用序列化方式,写到文本文件中去。因此DOM多用于写场景,而SAX/STAX多用于读场景。

  • 相关阅读:
    ubuntu 修改mysql 5.7数据库密码
    maven 配置
    数据仓库的命名规范
    mysql 之 在查询字段中得出分钟数
    mysql 之 timestampdiff() 函数 ,得到间隔分钟数
    linux 服务器上下载文件到本地
    mysql 之 时间格式 今年的第一天,去年的第一天
    mysql 之 str_to_date ()函数 和date_format()函数
    网络不可用时~更改DNS并刷新
    mysql之 round()函数 , concat()函数
  • 原文地址:https://www.cnblogs.com/xidongyu/p/12237933.html
Copyright © 2011-2022 走看看