XML解析

本文深入探讨了XML解析技术中的DOM与SAX两种方式,详细介绍了DOM解析的随机访问机制及其操作过程,以及SAX解析的顺序访问模式。通过示例代码展示了如何使用DOM和SAX解析XML文档,比较了两种方法的优缺点,并介绍了JDOM和DOM4J作为结合了两者优势的解决方案。最后,总结了XML解析在实际应用中的常见场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、简介

在得到一个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, 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建立解析器,然后通过文档依次找到根节点,再通过根节点找到每一个节点的内容。


资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在 IT 领域,文档格式转换是常见需求,尤其在处理多种文件类型时。本文将聚焦于利用 Java 技术栈,尤其是 Apache POI 和 iTextPDF 库,实现 doc、xls(涵盖 Excel 2003 及 Excel 2007+)以及 txt、图片等格式文件向 PDF 的转换,并实现在线浏览功能。 先从 Apache POI 说起,它是一个强大的 Java 库,专注于处理 Microsoft Office 格式文件,比如 doc 和 xls。Apache POI 提供了 HSSF 和 XSSF 两个 API,其中 HSSF 用于读写老版本的 BIFF8 格式(Excel 97-2003),XSSF 则针对新的 XML 格式(Excel 2007+)。这两个 API 均具备读取和写入工作表、单元格、公式、样式等功能。读取 Excel 文件时,可通过创建 HSSFWorkbook 或 XSSFWorkbook 对象来打开相应格式的文件,进而遍历工作簿中的每个 Sheet,获取行和列数据。写入 Excel 文件时,创建新的 Workbook 对象,添加 Sheet、Row 和 Cell,即可构建新 Excel 文件。 再看 iTextPDF,它是一个用于生成和修改 PDF 文档的 Java 库,拥有丰富的 API。创建 PDF 文档时,借助 Document 对象,可定义页面尺寸、边距等属性来定制 PDF 外观。添加内容方面,可使用 Paragraph、List、Table 等元素将文本、列表和表格加入 PDF,图片可通过 Image 类加载插入。iTextPDF 支持多种字体和样式,可设置文本颜色、大小、样式等。此外,iTextPDF 的 TextRenderer 类能将 HTML、
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值