XML 的 解析 :DOM 和 SAX

前端之家收集整理的这篇文章主要介绍了XML 的 解析 :DOM 和 SAX前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

按照DTD 或者 Schema 标准,写好一个 XML 文件之后,就需要将 XML 文件内容进行解析,以便于知道在这个XML文件中有什么内容,又有什么作用。那么怎么解析出这个 XML 的信息呢?有两种方式:DOM 和 SAX。其中,DOM方式是W3C 推荐的标准方式,但是 SAX 是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。


DOM:优点,对文档CRUD比较方便,但是内存占用较大

SAX:优点,占用内存小,解析速度快,但是只适合文档的读取,不适合CRUD


1、DOM

DOM 解析下,XML 文件的每一个组成部分都会用一个对象表示,例如标签用Element、属性用Attr,但是不管什么对象,都是Node的子类,所以在开发中把获得的任意节点都当做Node对象。这里就体现了JAVA中,一切皆对象的思想。

范例:

book.dtd

<!ENTITY bookName "Think in JAVA">
<!ELEMENT 书架 ANY>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>

<!ATTLIST 书名
	ISBN码 CDATA #IMPLIED
>
book.xml
<?xml version="1.0" ?>
<!DOCTYPE 书架 SYSTEM "book.dtd">
<书架>
	<书>
		<书名>&bookName;</书名>						<!-- 使用引用实体 -->
		<作者>海竹</作者>
		<售价>30.0</售价>
	</书>
	<书>
		<书名 ISBN码="521">WEB 实战经典</书名>			<!-- 自己定义,并使用“ISBN码”属性 -->
		<作者>西行</作者>
		<售价>29.9</售价>
	</书>
</书架>

DomDemo.java

package com.haizhu.xml;

import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class DomDemo {
	public void read() throws ParserConfigurationException,SAXException,IOException{
		// 创建工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 得到 COM 解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		// 解析 XML 文件,得到代表文档 的 document
		Document document = builder.parse("src/com/haizhu/xml/book.xml");
		// 读取出指定名称的节点,作为集合对象
		NodeList list = document.getElementsByTagName("书名");
		// 分别取出这个节点集合中的两个节点对象
		Node node = list.item(1);
		// 取出这个节点对象的内容
		String content = node.getTextContent();
		
		System.out.println(content);
	}
	public static void main(String[] args) throws ParserConfigurationException,IOException {
		DomDemo demo = new DomDemo();
		demo.read();
	}
}
结果:
WEB 实战经典

为了解析出书名中的“ISBN码”这个属性,我们可以运用向下转型的方法,将Node 对象转换成 Element 对象,这样就可以使用更多更方便操作的方法,如下所示:

package com.haizhu.xml;

import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class DomDemo {
	public void read() throws ParserConfigurationException,IOException{
		// 创建工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 得到 COM 解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		// 解析 XML 文件,得到代表文档 的 document
		Document document = builder.parse("src/com/haizhu/xml/book.xml");
		// 读取出指定名称的节点,作为集合对象
		NodeList list = document.getElementsByTagName("书名");
		// 分别取出这个节点集合中的两个节点对象
		Element node = (Element) list.item(1);							// 向下转型,因为我们确定这个集合就是 Element 对象
		// 取出这个节点对象的内容
		String content = node.getTextContent();
		String attr = node.getAttribute("ISBN码");						// 调用 取出对应名称属性方法
		System.out.println(content);
		System.out.println(attr);
	}
	public static void main(String[] args) throws ParserConfigurationException,IOException {
		DomDemo demo = new DomDemo();
		demo.read();
	}
}
结果:
WEB 实战经典
521

除了上面的读取信息,还有更多操作,比如增加删除修改等:

package com.haizhu.xml;

import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class DomDemo {
	public void read() throws ParserConfigurationException,IOException{
		// 创建工厂
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 得到 COM 解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		// 解析 XML 文件,得到代表文档 的 document
		Document document = builder.parse("src/com/haizhu/xml/book.xml");
		// 读取出指定名称的节点,作为集合对象
		NodeList list = document.getElementsByTagName("书名");
		// 分别取出这个节点集合中的两个节点对象
		Element node = (Element) list.item(1);							// 向下转型,因为我们确定这个集合就是 Element 对象
		// 取出这个节点对象的内容
		String content = node.getTextContent();
		String attr = node.getAttribute("ISBN码");						// 调用 取出对应名称属性方法
		System.out.println(content);
		System.out.println(attr);
	}

	public void add() throws ParserConfigurationException,IOException,TransformerException{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse("src/com/haizhu/xml/book.xml");
		
		// ***********************先增加一本书**************************
		// 创建一个书的节点对象
		Element book = (Element)document.createElement("书");
		// 取出书的父节点对象,也就是根节点,注意根节点不需要名称
		Element bookShelf = (Element)document.getDocumentElement();
		// 将书添加到父节点
		bookShelf.appendChild(book);
		
		// ***********************为一本书增加书名,作者,售价**************************
		// 跟上面的步骤是一样的,如下:
		Element bookName = (Element)document.createElement("书名");
		Element author = (Element)document.createElement("作者");
		Element price = (Element)document.createElement("售价");
		bookName.setTextContent("Steve Jobs");
		author.setTextContent("Walter Isaacson");
		price.setTextContent("106.0");
		book.appendChild(bookName);
		book.appendChild(author);
		book.appendChild(price);

		// ***********************增加  属性**************************
		bookName.setAttribute("ISBN码","U R NO.1 !");
		
		// ***********************更新xml文档**************************
		// 上面的操作指示把内容写进了内存,但是没有写入xml文档,需要如下操作:
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		transformer.transform(new DOMSource(document),new StreamResult(new FileOutputStream("src/com/haizhu/xml/book.xml")));
	}
	
	public void delete() throws ParserConfigurationException,TransformerException {
		// 得到 document
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse("src/com/haizhu/xml/book.xml");
		// 得到Element
		Element toDelete = (Element)document.getElementsByTagName("售价").item(0);
		Element dFather = (Element)document.getElementsByTagName("书").item(0);
		// 移除
		dFather.removeChild(toDelete);
		// 提交
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		transformer.transform(new DOMSource(document),new StreamResult(new FileOutputStream("src/com/haizhu/xml/book.xml")));
	}

public static void main(String[] args) throws ParserConfigurationException,TransformerException {
		DomDemo demo = new DomDemo();
		demo.read();
		demo.add();
		demo.delete();
	}
}


2、SAX

2.1 SAX 采用事件处理的方式解析XML 文件,利用SAX 解析 XML 文件,涉及两个部分:解析器和事件处理器:

a、解析器可以使用 JAXP 的API 创建,创建出 SAX 解析器后,就可以知道你个解析器去解析某个 XML 文档。

b、解析器采用 SAX 方式在解析某个 XML 文档时,它只要解析到 XML 文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把它当前解析到的 XML 文件内容作为 方法的参数 传递给事件处理器。

c、事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松的得到 sax 解析器解析到的数据,从而可以决定如何对数据进行处理。

package com.haizhu.xml;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class SAXDemo {
	public static void main(String[] args) throws ParserConfigurationException,IOException {
		// 1、创建工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
		// 2、得到解析器
		SAXParser saxParser = factory.newSAXParser();
		// 3、得到读取器
		XMLReader reader = saxParser.getXMLReader();
		// 4、设置内容处理器,每个处理器有自己的处理方法
		//reader.setContentHandler(new ListHandler());
		//reader.setContentHandler(new NeedTagValueHandler());
		reader.setContentHandler(new NeedTagValueHandler());
		// 5、读取xml文档
		reader.parse("src/com/haizhu/xml/book.xml");
	}
}

// 取出 XML 中所有的内容
class ListHandler implements ContentHandler{

	// 开始
	@Override
	public void startElement(String uri,String localName,String qName,Attributes atts) throws SAXException {
		System.out.println("<"+qName+">");
		// 循环取出属性,注意中间的判断可以使用 “ && ”
		for(int i=0;atts!=null && i<atts.getLength();i++){
			String attName = atts.getQName(i);
			String attValue = atts.getValue(i);
			System.out.println(attName+" = "+attValue);
		}
	}

	// 结束
	@Override
	public void endElement(String uri,String qName)
			throws SAXException {
		System.out.println("</"+qName+">");
	}

	// 内容
	@Override
	public void characters(char[] ch,int start,int length)
			throws SAXException {
		System.out.println(new String(ch,start,length));
	}


	
	
	@Override
	public void setDocumentLocator(Locator locator) {}

	@Override
	public void startDocument() throws SAXException {}

	@Override
	public void endDocument() throws SAXException {}

	@Override
	public void startPrefixMapping(String prefix,String uri)
			throws SAXException {}

	@Override
	public void endPrefixMapping(String prefix) throws SAXException {}

	@Override
	public void ignorableWhitespace(char[] ch,int length)
			throws SAXException {}

	@Override
	public void processingInstruction(String target,String data)
			throws SAXException {}

	@Override
	public void skippedEntity(String name) throws SAXException {}
	
}

//取出 XML 中指定属性的值
class TagValueHandler extends DefaultHandler{					// 继承这个类就可以选择的覆写需要的方法,而不用全部覆写

	private String currentTag;	// 记住当前解析到的标签内容
	
	// 开始
	@Override
	public void startElement(String uri,Attributes atts) throws SAXException {
		currentTag = qName;
	}
	// 结束
	@Override
	public void endElement(String uri,String qName)
			throws SAXException {
		currentTag = null;
	}
	// 内容
	@Override
	public void characters(char[] ch,int length)
			throws SAXException {
		if("作者".equals(currentTag)){
			System.out.println(new String(ch,length));
		}
	}

}

//上面的例子取出了所有的作者,能不能取出指定的第N位作者的名字呢?如下:
class NeedTagValueHandler extends DefaultHandler{

	private String currentTag;
	private int needNum = 2;	// 想获取第几个作者的值
	private int currentNum;
	
	// 开始
	@Override
	public void startElement(String uri,Attributes atts) throws SAXException {
		currentTag = qName;
		if(currentTag.equals("作者")){
			currentNum++;
		}
	}
	// 结束
	@Override
	public void endElement(String uri,int length)
			throws SAXException {
		if("作者".equals(currentTag) && currentNum==needNum){
			System.out.println(new String(ch,length));
		}
	}
}
原文链接:https://www.f2er.com/xml/299979.html

猜你在找的XML相关文章