zoukankan      html  css  js  c++  java
  • 无废话XML--XML解析(DOM和SAX)

    • XML处理模式

    处理XML有2种方式,DOM和SAX。一般的实际开发中,这2种使用的不多,直接用dom4j来解析XML就好了,包括CRUD等操作都很方便的。这里介绍的DOM和SAX是比较底层的,具体的API在jdk中可以查到的。




    • 一、 DOM 文档对象模式
        1.DOM特点:
          以树型结构访问XML文档。 一棵DOM树包含全部元素节点和文本节点。可以前后遍历树中的每一个节点。
          整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能。      将整个文档调入内存(包括无用的节点),浪费时间和空间。      一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)情况下使用。
        2.DOM树与节点
          XML文档被解析成树型结构。      树由节点组成。共有12种不同的节点。      节点可以包含其他节点(依赖于节点的类型)。      父节点包含子节点。叶子节点没有子节点。
        3.节点类型

          知道下面这3种比较常用的就好了:Document(节点)      Element(元素)      Attribute(属性)

    import java.io.File;
    import java.io.IOException;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import org.w3c.dom.Attr;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.NamedNodeMap;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import org.xml.sax.SAXException;
    
    public class LinkinDOMParser
    {
    
    	public static void main(String[] args) throws SAXException, IOException, ParserConfigurationException
    	{
    		//创建一个DOM解析器工厂
    		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    		//从工厂中生成一个DOM解析器; throws ParserConfigurationException
    		DocumentBuilder builder = factory.newDocumentBuilder();
    		//绑定需要解析的XML文件
    		File xmlFile = new File("src/data-sources.xml");//相对地址,相对于这个工程		
    		//开始解析 ;throws SAXException,IOException
    		Document document = builder.parse(xmlFile);
    		//取出唯一的根元素
    		Element rootElement = document.getDocumentElement();
    		//调用业务方法: 遍历根元素
    		printElement(rootElement);
    	}
    
    	/** 遍历元素,包含: 子元素、属性、文本内容 */
    	private static void printElement(Element e)
    	{
    		//打印出元素的标签名
    		System.out.print("<" + e.getTagName());
    		//获取开始标签的属性
    		NamedNodeMap attMap = e.getAttributes();
    		//循环遍历所有的属性
    		for (int i = 0; i < attMap.getLength(); i++)
    		{
    			Attr attr = (Attr) attMap.item(i);
    			System.out.print(" " + attr.getName() + "=" + attr.getValue());
    		}
    		System.out.print(">");
    
    		//获取当前元素的所有子节点
    		NodeList nl = e.getChildNodes();
    		for (int j = 0; j < nl.getLength(); j++)
    		{
    			Node n = nl.item(j);
    			if (Node.ELEMENT_NODE == n.getNodeType())// getNodeType:表示基础对象的类型的节点,如上所述。
    			{
    				printElement((Element) n);//递归调用,以遍历下一个元素
    			}
    			else
    			{
    				System.out.print(n.getTextContent());
    			}
    		}
    		//打印结束标签
    		System.out.print("</" + e.getTagName() + ">");
    	}
    
    }
    

    <?xml version="1.0" encoding="UTF-8"?>
    <DataSource>
    	<database name="mysql" version="5.0">
    		<driver>com.mysql.jdbc.Driver</driver>
    		<url>jdbc:mysql://localhost:3306/linkinjdbc</url>
    		<user>root</user>
    		<password>root</password>
    	</database>
    
    	<database name="Oracle" version="10G">
    		<driver>oracle.jdbc.driver.OracleDriver</driver>
    		<url>jdbc:oracle:thin:@127.0.0.1:linkinOracle</url>
    		<user>system</user>
    		<password>root</password>
    	</database>
    </DataSource>




          


    • 二、 SAX 基于事件处理模式

        解析器向一个事件处理程序发送事件,比如元素开始和元素结束,而事件处理器则处理该信息。    然后应用程序本身就能够处理该数据。原始的文档仍然保留完好无损。

    1. 为什么会出现 SAX 解析?
    在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个DOM 树的 Doucment 对象,从而再对 XML 文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。SAX 解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。注意:sax 只能用于读取 xml 文件,无法作更新
    2. SAX 采用事件处理的方式解析 XML 文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器(对象):解析器可以使用 JAXP 的 API 创建,创建出 SAX 解析器后,就可以指定解析器去解析某个 XML 文档。解析器采用 SAX 方式在解析某个 XML 文档时, 它只要解析到 XML 文档的一个组成部分,都会去调用事件处理器的一个方法, 解析器在调用事件处理器的方法时, 会把当前解析到的xml 文件内容作为方法的参数传递给事件处理器。事件处理器由程序员编写, 程序员通过事件处理器中方法的参数, 就可以很轻松地得到sax 解析器解析到的数据,从而可以决定如何对数据进行处理。

    import java.io.InputStream;
    import javax.xml.parsers.SAXParser;
    import javax.xml.parsers.SAXParserFactory;
    import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.DefaultHandler;
    
    /**
     * 
     * @version 1L
     * @author LinkinPark
     * @since 2014-12-26
     * @motto 梦似烟花心似水,同学少年不言情   
     * @desc ^ 	DefaultHandler:SAX2 事件处理程序的默认基类。 
     * 		   	SAXParserFactory:定义工厂API,使应用程序能够配置和获取基于 SAX 的解析器以解析 XML 文档。 
     * 			SAXParser:定义包装 XMLReader 实现类的API。获取此类的实例之后,将可以从各种输入源解析 XML。
     * 			写此程序旨在理解Java的事件驱动默认,在JavaME编程中这种事件很多的。其实和js和中的事件一样的。
     */
    public class LinkinSaxHandler extends DefaultHandler
    {
    
    	@Override
    	//接收文档开始的通知。
    	public void startDocument() throws SAXException
    	{
    		super.startDocument();
    		System.out.println("开始解析XML文档。。。");
    	}
    
    	@Override
    	//接收文档结束的通知。
    	public void endDocument() throws SAXException
    	{
    		super.endDocument();
    		System.out.println("解析XML文档结束。。。");
    	}
    
    	@Override
    	//接收元素开始的通知。
    	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    	{
    		super.startElement(uri, localName, qName, attributes);
    		System.out.println("开始解析元素[" + qName + "]。。。");
    		System.out.println("共有[" + attributes.getLength() + "]个属性。。。");
    		for (int i = 0; i < attributes.getLength(); i++)
    		{
    			System.out.println("属性名是:"+attributes.getLocalName(i)+";属性值是:"+attributes.getValue(i));
    		}
    	}
    
    	@Override
    	//接收元素结束的通知。
    	public void endElement(String uri, String localName, String qName) throws SAXException
    	{
    		super.endElement(uri, localName, qName);
    		System.out.println("解析元素[" + qName + "]结束。。。");
    	}
    
    	@Override
    	//接收元素中字符数据的通知。
    	public void characters(char[] ch, int start, int length) throws SAXException
    	{
    		super.characters(ch, start, length);
    		String content = new String(ch, start, length);
    		System.out.println("开始接受元素中的字符串数据。。。");
    		System.out.println(content);
    	}
    
    	public static void main(String[] args) throws Exception
    	{
    		SAXParserFactory factory = SAXParserFactory.newInstance();
    		SAXParser parser = factory.newSAXParser();
    		//使用相对路径来获得一个资源的流
    		InputStream is = ClassLoader.getSystemResourceAsStream("data-sources.xml");
    		parser.parse(is, new LinkinSaxHandler());
    	}
    
    }
    

    <?xml version="1.0" encoding="UTF-8"?>
    <DataSource>
    	<database name="mysql" version="5.0">
    		<driver>com.mysql.jdbc.Driver</driver>
    		<url>jdbc:mysql://localhost:3306/linkinjdbc</url>
    		<user>root</user>
    		<password>root</password>
    	</database>
    
    	<database name="Oracle" version="10G">
    		<driver>oracle.jdbc.driver.OracleDriver</driver>
    		<url>jdbc:oracle:thin:@127.0.0.1:linkinOracle</url>
    		<user>system</user>
    		<password>root</password>
    	</database>
    </DataSource>


    import javax.xml.parsers.SAXParser;
    import javax.xml.parsers.SAXParserFactory;
    import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.SAXParseException;
    import org.xml.sax.helpers.DefaultHandler;
    
    public class LinkinSaxHandler extends DefaultHandler
    {
    
    	/** 基于SAX方式解析XML文档 */
    	public static void main(String[] args) throws Exception
    	{
    		SAXParserFactory factory = SAXParserFactory.newInstance(); //创建SAX解析器工厂
    		factory.setValidating(true); //让error方法生效
    		SAXParser parser = factory.newSAXParser(); //生成一个具体的SAX解析器
    		parser.parse("src/data-sources.xml", new LinkinSaxHandler()); //开始解析
    	}
    
    	// 只需覆盖我们感兴趣的方法
    	private int counter = 0;// 定义一个计数器,保存XML文档触发事件的次数
    
    	@Override
    	// 文档开始事件触发
    	public void startDocument() throws SAXException
    	{
    		counter++;
    		System.out.println(counter + ".解析XML文件开始...");
    	}
    
    	@Override
    	// 文档结束事件触发
    	public void endDocument() throws SAXException
    	{
    		counter++;
    		System.out.println("
    " + counter + ".解析XML文件结束...");
    	}
    
    	@Override
    	// 元素开始事件触发
    	public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException
    	{
    		counter++;
    		System.out.print(counter + ".<" + qName);
    		for (int i = 0; i < atts.getLength(); i++)
    		{ //读取标志的所有属性
    			System.out.print(" " + atts.getLocalName(i) + "=" + atts.getValue(i));
    		}
    		System.out.print(">");
    	}
    
    	@Override
    	// 元素结束事件触发
    	public void endElement(String uri, String localName, String qName) throws SAXException
    	{
    		counter++;
    		System.out.print(counter + ".</" + qName + ">");
    	}
    
    	@Override
    	// 文本事件触发  打印时尽量不要换行,否则很难看
    	public void characters(char[] ch, int start, int length) throws SAXException
    	{
    		counter++;
    		String text = new String(ch, start, length); // 当前元素的文本值
    		System.out.print(counter + ".Text=" + text);
    	}
    
    	@Override
    	//这是可恢复错误。需在SAXParserFactory设置有效性错误才能生效
    	public void error(SAXParseException e) throws SAXException
    	{
    		System.out.println("xml文档有效性错误:" + e);
    	}
    
    	@Override
    	//严重错误
    	public void fatalError(SAXParseException e) throws SAXException
    	{
    		System.out.println("xml文档严重的有效性错误:" + e);
    	}
    
    }
    



    • 三、 比较DOM与SAX:
        DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问
        优点:1.提供随机定义元素操作,来回移动指针。         2.将整个XML文件一次性加载到内存,形成虚的内存树。
        缺点:1.如果XML文件较大,内存空间占用较大。         2.强制将较大的XML文件加载到内存中,有可能损害文件         3.功能通用性

        SAX:不同于DOM,SAX是事件驱动型的XML解析方式。它顺序逐行读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对    XML的顺序访问 


        总结:DOM在做CRUD都比较方便,但不适合解析大的XML文档。SAX占用资源比较少,但只适合读取XML。
  • 相关阅读:
    openlayers5之ol.proj坐标转换
    bootstrap模态框可拖动 --------------------- 本文来自 gisdoer 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/gisdoer/article/details/82838312?utm_source=copy
    bootstrap模态框可拖动
    leaflet实用插件整理
    面试题经常问的闭包问题
    撩课-Java每天5道面试题第15天
    撩课-Web大前端每天5道面试题-Day4
    撩课-Python-每天5道面试题-第4天
    撩课-Java每天5道面试题第14天
    撩课-Web大前端每天5道面试题-Day3
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5233112.html
Copyright © 2011-2022 走看看