您的位置:首页 > 其它

XML解析

2013-10-31 10:27 591 查看
一、简介

在得到一个XML文档之后,利用程序按照其中元素的定义名称取出对应的内容,这样的操作即为:XML解析。在XML解析中,W3C定义了SAX和DOM两种解析方式,者两种解析方式的程序操作如下图所示:



由上图即可发现,应用程序不是直接对XMl文档进行操作的,而是先由XML分析器对文档进行分析,然后应用程序通过XML分析器所提供的DOM接口或SAX接口对分析结果进行操作,从而间接地实现了对XML文档的访问。

二、DOM解析操作

基于DOM(Document Object Model, 文档对象模型)的XML解析器将一个XML文档转换成一个对象模型的集合(即:DOM树),应用程序通过对这个对象模型的操作,来实现对XNL文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此这种利用DOM接口的机制也被称为随机访问机制。DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,可以任意的控制整个XML文档中的内容。但是,由于DOM分析器把整个XML文档转化成DOM树放在内存中,因此,此文档比较大或者结构比较复杂时,堆内存的要求就比较高,而且对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对及其性能的要求比较高,程序的效率并不十分理想。

package com.wbf.dom;

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

public class TestDOMDemo {

public static void main(String args[])
{
//建立DocumentBuilderFactory,用于取得DocumentBuilder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//建立DocumentBuilder
DocumentBuilder builder = null;
//实例化Document
Document doc = null;
try {
builder = factory.newDocumentBuilder();
//读取指定路径的xml文档
doc = builder.parse("d:" + File.separator + "dom_demo_1.xml");
//查找tagName="name"的节点
NodeList nl = doc.getElementsByTagName("name");
int len = nl.getLength();
for (int i = 0; i < len; i++)
{
//输出文本节点的内容
System.out.println(nl.item(i).getFirstChild().getNodeValue());
}

} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果:

                   张三

                   李四

XML源文件dom_demo_1.xml内容:

<?xml version="1.0" encoding="GBK"?>
<addresslist>
<linkman>
<name>张三</name>
<email>zhangsan@qq.com</email>
</linkman>
<linkman>
<name>李四</name>
<email>lisi@qq.com</email>
</linkman>
</addresslist>

以上程序完成了一个简单的DOM解析操作,从指定的XML文件中读取指定节点的内容,当使用builder.parse()操作时实际上就相当于将所有的XML文档读取到内存中,从而将所有的XML文件内容按照节点的定义顺序将其变成一颗内存中的DOM树,供用户解析使用。

在DOM操作中,除了可以使用DOM完成XML的读取之外,还可以使用DOM进行XML文件的新建输出。此时就需要必须newDocument方法建立一个新的DOOM树,并手工设置各个节点的关系。
package com.wbf.dom;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
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;

public class TestDOMDemo1 {

public static void main(String args[]) throws Exception
{
//建立DocumentBuilderFactory,用于取得DocumentBuilder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//建立DocumentBuilder
DocumentBuilder builder = factory.newDocumentBuilder();
//新建一个Document文档
Document doc = builder.newDocument();
//建立各个操作节点
Element addresslist = doc.createElement("addresslist");
Element linkman = doc.createElement("linkman");
Element name = doc.createElement("name");
Element email = doc.createElement("email");
//为需要节点添加文本节点
name.appendChild(doc.createTextNode("张三"));
email.appendChild(doc.createTextNode("zhangsan@qq.com"));
//设置节点关系
linkman.appendChild(name);
linkman.appendChild(email);
addresslist.appendChild(linkman);
doc.appendChild(addresslist);

//输出文档到文件中
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.ENCODING, "GBk");//设置编码格式
DOMSource source = new DOMSource(doc);//输出文档
//设置输出位置
StreamResult result = new StreamResult(new File("d:" + File.separator + "dom_demo_2.xml"));
//输出
t.transform(source, result);
}
}

运行结果文件dom_demo_2.xml:
<?xml version="1.0" encoding="GBk" standalone="no"?>
<addresslist>
<linkman>
<name>张三</name>
<email>zhangsan@qq.com</email>
</linkman>
</addresslist>

以上程序可以发现,在XML创建中的所有节点(ELement)都是通过Document接口创建的,在创建时本身并没有任何父子节点关系,而是通过appendChild()方法设置的,而且根节点(addresslist)也要加入到document中,这样才是一棵完整的DOM。从以上两个demo中可以发现,使用DOM操作不仅可以读取文件,本身也可以生成和修改XML文件。

三、SAX解析操作

SAX(Simple APIS for XML, 操作XML的简单接口),采用的是一种顺序的模式进行访问,是一种快速读取XML数据的方式。如果在开发中想要使用SAX解析,则首先应该编写一个SAX解析器,再直接定义一个类,并使该类继承自DefaultHandler类,同时覆写其方法即可。当使用SAX解析器进行操作时会触发一系列的事件,如:当扫描到文档开始与结束、元素开始与结束是都会调用相关的处理方法,并由这些操作方法做出相应的操作,直至整个文档扫描结束。

新建解析器,继承DefaultHandler类:

package com.wbf.sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class MySAX extends DefaultHandler {

@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
/* 接收元素中字符数据的通知
* 默认情况下,不执行任何操作。
* 应用程序编写者可以重写此方法,以便对每块字符数据采取特定的措施(如将该数据添加到节点或缓冲区,或者将该数据打印到文件)。
* */
System.out.println(new String(ch, start, length));
}

@Override
public void endDocument() throws SAXException {
/* 接收文档结束的通知。
* 默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在文档的结束处采取特定的操作(如,结束树或关闭输出文件)。
* */
System.out.println("\n文档读取结束。。。");
}

@Override
public void endElement(String uri
4000
, String localName, String qName)
throws SAXException {
/* 接收元素结束的通知。
* 默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在每个元素的结束处采取特定的操作(如,结束树节点或将输出写入文件)。
* */
System.out.print("</");
System.out.print(qName);//输出元素名称
System.out.print(">");

}

@Override
public void startDocument() throws SAXException {
/* 接收文档开始的通知。
* 默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在文档的开始采取特定的措施(如分配树的根节点或创建输出文件)。
* */
System.out.println("<?xml version=\"1.0\" encoding=\"GBK\"?>");
}

@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
/* 接收元素开始的通知。
* 默认情况下,不执行任何操作。应用程序编写者可以在子类中重写此方法,以便在每个元素的开始处采取特定的操作(如,分配新的树节点或将输出写入文件)。
* */
System.out.print("<");
System.out.print(qName);
if (attributes != null){
for (int i = 0; i < attributes.getLength(); i++){
System.out.print(" " + attributes.getQName(i) + "=\""
+ attributes.getValue(i) + "\"");
}
}
System.out.println(">");
}
}

使用SAX解析器:
package com.wbf.sax;

import java.io.File;

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

public class TestSAXDemo {

public static void main(String[] args) throws Exception {
//建立SAX解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//构造解析器
SAXParser parser = factory.newSAXParser();
//使用DefaultHandler解析XML
parser.parse("d:" + File.separator + "sax_demo_1.xml", new MySAX());
}
}

被解析XML文档sax_demo_1.xml:
<?xml version="1.0" encoding="GBK"?>
<addresslist>
<linkman>
<name>张三</name>
<email>zhangsan@qq.com</email>
</linkman>
<linkman>
<name>李四</name>
<email>lisi@qq.com</email>
</linkman>
</addresslist>

四、DOM解析和SAX解析比较



既然DOM解析适合于修改,SAX解析适合于读取大文件,那么如果将两者的优点集合起来操作岂不是更加方便?如:JDOM、DOM4J等。

五、JDOM

JDOM是使用Java语言编写的,用于读、写、操作XML的一套组件。一定要记住:JDOM = DOM修改文件的优点 + SAX读取快速的优点 。

1)使用JDOM进行XML的写操作(新建):

package com.wbf.jdom;

import java.io.File;
import java.io.FileOutputStream;

import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.XMLOutputter;

public class WriteXML {

public static void main(String[] args) throws Exception {

Element addresslist = new Element("addresslist");//定义根节点
Element linkman = new Element("linkman");//定义linkman节点
Element name = new Element("name");//定义name节点
Element email = new Element("email");//定义email节点

Attribute id = new Attribute("id", "zs");//定义属性
Document doc = new Document(addresslist);//定义一个document对象,并设置根节点

//设置节点的文本节点
name.setText("zhangsan");
email.setText("zhangsan@qq.com");
//设置节点的属性
linkman.setAttribute(id);
//设置节点的父子关系
linkman.addContent(name);
linkman.addContent(email);
addresslist.addContent(linkman);

XMLOutputter out = new XMLOutputter();//用来输出XML文件
out.setFormat(out.getFormat().setEncoding("GBK"));//设置输出的编码格式
//输出XML文件
out.output(doc, new FileOutputStream("d:" + File.separator + "jdom_demo_1.xml"));

}
}

被JDOM新建的XML文档jdom_demo_1.xml:
<?xml version="1.0" encoding="GBK"?>
<addresslist>
<linkman id="zs">
<name>zhangsan</name>
<email>zhangsan@qq.com</email>
</linkman>
</addresslist>

2)使用JDOM进行XML的读操作:
package com.wbf.jdom;

import java.io.File;
import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

public class ReadXML {
public static void main(String[] args) throws Exception {

//使用JDOM读取XML文件
SAXBuilder builder = new SAXBuilder();//建立SAX解析
//被解析的XML文档
Document read_doc = builder.build("d:" + File.separator + "jdom_demo_1.xml");
Element root = read_doc.getRootElement();
List<Element> elements = root.getChildren("linkman");
for (int i = 0; i < elements.size(); i++)
{
Element e = elements.get(i);//取出一个linkman子元素
String name = e.getChildText("name");//取得name元素内容或文本节点的value
String id = e.getAttribute("id").getValue();//获取linkman节点的属性id
//String email = e.getChild("email").getText();//取得email元素内容
//String email = e.getChild("email").getValue();//取得email元素内容
String email = e.getChildText("email");//与前两句等价

System.out.println("------联系人-----");
System.out.println("姓名: " + name + " 编号: " + id);
System.out.println("EMAIL:" + email);
System.out.println("----------------");
System.out.println();
}
}
}

其中jdom_demo_1.xml即为前文中所示。
六、DOM4J

DOM4J也是一组XML操作的组件包,主要用来读写XML文件。由于DOM4J性能优异,功能强大,而且易用性强,所以应用广泛,如:Hibernate和Spring框架中都使用了DOM4J进行XML的解析操作。其操作与JDOM类似。

1)使用DOM4进行XML的写操作:

package com.wbf.dom4j;

import java.io.File;
import java.io.FileOutputStream;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

public class Dom4JWriter {
public static void main(String[] args) throws Exception {

Document doc = DocumentHelper.createDocument();//新建文档
Element addresslist = doc.addElement("addresslist");//定义根节点
Element linkman = addresslist.addElement("linkman");//定义子节点
Element name = linkman.addElement("name");//定义子节点
Element email = linkman.addElement("email");//定义子节点
linkman.addAttribute("id", "zs");
name.setText("张三");//设置name节点内容
email.setText("zhangsan@qq.com");//设置email节点内容
OutputFormat format = OutputFormat.createPrettyPrint();//设置输出格式
format.setEncoding("GBK");
//指定输出目标文件和格式
XMLWriter writer = new XMLWriter(new FileOutputStream(new File("d:" + File.separator + "dom4j_demo_1.xml")), format);
//输出文件内容
writer.write(doc);
//关闭输出流
writer.close();
}
}

输出的XML文档如下:

<?xml version="1.0" encoding="GBK"?>
<addresslist>
<linkman id="zs">
<name>张三</name>
<email>zhangsan@qq.com</email>
</linkman>
</addresslist>

2)使用DOM4进行XML的读操作:
package com.wbf.dom4j;

import java.io.File;
import java.util.Iterator;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class DOM4JReader {
public static void main(String[] args) throws Exception{

//新建即将被读取的文件
File file = new File("d:" + File.separator + "dom4j_demo_1.xml");
SAXReader reader = new SAXReader();//建立SAX解析
Document doc = reader.read(file);//读取文档
Element root = doc.getRootElement();//获取根节点
Iterator iter = root.elementIterator();
while(iter.hasNext())
{
Element linkman = (Element)iter.next();
System.out.println("姓名: " + linkman.elementText("name") + ", 编号: " + linkman.attributeValue("id"));
System.out.println("邮件: " + linkman.elementText("email"));
}
}
}

程序运行结果:
                       姓名: 张三, 编号: zs

                       邮件: zhangsan@qq.com

七、总结

从以上程序中可以看出,读取文件需要使用SAX建立解析器,然后通过文档依次找到根节点,再通过根节点找到每一个节点的内容。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  XML解析 jdom dom4j SAX DOM