Java解析XML

一、XML常见解析方式

常见解析XML的方法主要有DOM和SAX

1.DOM解析方式-基于文档树

DOM,即文档对象模型(Document Object Model),将XML文档解析成树状模型并将其放入内存来完成解析工作的,而后对文档的操作都是在这个树状模型上完成的。这个在内存中的文档树将是文档实际大小的几倍。

2.SAX解析方式-事件驱动

即XML简单应用程序接口-Simple API for XML,通读整个文档,根据文档内容产生事件,而把对这些事件的处理交由事件处理器处理。

3.DOM与SAX解析方式的对比

SAX DOM
顺序读入文档并产生相应事件,可以处理任何大小的XML文档 在内存中创建文档树,不适于处理大型XML文档。
只能对文档按顺序解析一遍,不支持对文档的随意访问。 可以随意访问文档树的任何部分,没有次数限制。
只能读取XML文档内容,而不能修改 可以随意修改文档树,从而修改XML文档。
开发上比较复杂,需要自己来实现事件处理器。 易于理解,易于开发。
对开发人员而言更灵活,可以用SAX创建自己的XML对象模型。 已经在DOM基础之上创建好了文档树。

二、Java中解析XML

Sun公司提供了 java API for XML Parsing(JAXP)接口来使用SAX和DOM,通过JAXP,我们可以使用任何与JAXP兼容的XML解析器。

1.基础类与待解析XML

<?xml version="1.0" encoding="UTF-8"?>
<MemInfo class="0501">
	<person no="1">
		<name>James</name>
		<age>32</age>
	</person>
	<person no="2">
		<name>Kim</name>
		<age>38</age>
	</person>
	<person no="3">
		<name>Joe</name>
		<age>24</age>
	</person>
</MemInfo>
public class ClassInfo {
	private String no;
	private List<Person> students;

	public String getNo() {
		return no;
	}

	public void setNo(String no) {
		this.no = no;
	}

	public List<Person> getStudents() {
		return students;
	}

	public void setStudents(List<Person> students) {
		this.students = students;
	}
}
public class Person {
	private String no;
	private String name;
	private byte age;

	public String getNo() {
		return no;
	}

	public void setNo(String no) {
		this.no = no;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public byte getAge() {
		return age;
	}

	public void setAge(byte age) {
		this.age = age;
	}
}

 2.SAX方式解析

import java.util.ArrayList;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.alibaba.fastjson.JSONObject;

/**
 * SAX解析器
 */
public class MemInfoParser extends DefaultHandler {
	/**
	 * log4j日志
	 */
	protected static Logger log = LogManager.getLogger();

	private ClassInfo cls;
	private Person person;
	/**
	 * 
	 */
	private String preTag;

	/**
	 * 文档开始调用
	 */
	@Override
	public void startDocument() throws SAXException {
		cls = new ClassInfo();
		cls.setStudents(new ArrayList<>());
	}

	/**
	 * 文档结束调用
	 */
	@Override
	public void endDocument() throws SAXException {
		log.info("解析获得数据:" + JSONObject.toJSONString(cls));
	}

	/**
	 * 元素处理开始调用-多次
	 */
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		switch (qName) {
		case "MemInfo":
			cls.setNo(attributes.getValue("class"));
			break;
		case "person":
			person = new Person();
			person.setNo(attributes.getValue("no"));
			break;
		default:
			break;
		}
		preTag = qName;
	}

	/**
	 * 元素处理结束调用-多次
	 */
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		switch (qName) {
		case "MemInfo":
			break;
		case "person":
			cls.getStudents().add(person);
			person = null;
			break;
		default:
			break;
		}
		preTag = null;
	}

	/**
	 * 处理TextNode文本节点调用-多次
	 */
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		//preTag为空,表示处理的是空白的文本节点,丢弃掉,PS:元素之间的空白部分SAX解析器会作为文本节点处理,如person、name节点间的空白
		if (preTag == null)
			return;
		// 文本内容
		String text = new String(ch, start, length);
		switch (preTag) {
		case "name":
			person.setName(text);
			break;
		case "age":
			person.setAge(Byte.parseByte(text));
			break;
		default:
			break;
		}
	}
}

 测试类:

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

import org.xml.sax.XMLReader;

public class SaxParserTest {
	public static void main(String[] args) throws Exception {
		String path = "/data/workspace/tec-demo/src/main/java/cn/tinyf/demo/xml/sax/MemInfo.xml";
		// 创建解析工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
		// 创建解析器
		SAXParser parser = factory.newSAXParser();
		// 得到读取器
		XMLReader reader = parser.getXMLReader();
		// 设置内容处理器
		MemInfoParser handler = new MemInfoParser();
		reader.setContentHandler(handler);
		// 读取xml文档
		reader.parse(path);
	}
}

3.DOM方式读写

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

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;

import com.alibaba.fastjson.JSONObject;

/**
 * XML解析-Dom实现
 */
public class MemInfoParser {

	public static void main(String[] args) {
		String path = "/data/workspace/tec-demo/src/main/java/cn/tinyf/demo/xml/MemInfo.xml";
		System.out.println(JSONObject.toJSONString(parser(path)));
	}

	public static ClassInfo parser(String docPath) {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 从 DocumentBuilderFactory获取 DocumentBuilder实例
		DocumentBuilder db;
		try {
			// 从 XML 文档获取 DOM 文档实例
			db = dbf.newDocumentBuilder();
			Document doc = db.parse(new File(docPath));
			/*
			 * 创建相关对象存储XML数据
			 */
			ClassInfo cls = new ClassInfo();
			List<Person> stuList = new ArrayList<>();
			cls.setStudents(stuList);
			// 获取文档节点中的班级信息
			cls.setNo(doc.getDocumentElement().getAttribute("class"));
			/*
			 * 获取所有学生节点,并遍历获取数据
			 */
			NodeList stuNodes = doc.getElementsByTagName("person");
			int len = stuNodes.getLength();
			for (int i = 0; i < len; i++) {
				Element stu = (Element) stuNodes.item(i);
				Node eltName = stu.getElementsByTagName("name").item(0);
				Node eltAge = stu.getElementsByTagName("age").item(0);
				Person person = new Person();
				person.setName(eltName.getFirstChild().getNodeValue());
				person.setNo(stu.getAttribute("no"));
				person.setAge(Byte.parseByte(eltAge.getFirstChild().getNodeValue()));
				stuList.add(person);
			}
			return cls;
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}
/**
 * XML生成-dom方式
 */
public class MemInfoBuilder {
	/**
	 * log4j2日志
	 */
	protected static Logger log = LogManager.getLogger();

	public static void main(String[] args) {
		String xmlPath = "/data/workspace/tec-demo/src/main/java/cn/tinyf/demo/xml/dom/dom-data.xml";
		//
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 从 DocumentBuilderFactory获取 DocumentBuilder实例
		DocumentBuilder db;
		try {
			// 从 XML 文档获取 DOM 文档实例
			db = dbf.newDocumentBuilder();
			Document doc = db.newDocument();
			/*
			 * 生成文档树
			 */
			// 根节点
			Element root = doc.createElement("MemInfo");
			// 设置根节点属性
			root.setAttribute("class", "0501");
			// 为根节点添加子节点数据
			root.appendChild(createStuElement(doc, "1", "James", 32));
			root.appendChild(createStuElement(doc, "2", "Kim", 38));
			root.appendChild(createStuElement(doc, "3", "Joe", 24));
			// 根节点添加到文档树
			doc.appendChild(root);
			/*
			 * 准备生成文件
			 */
			// 设置XML声明中standalone为yes,即没有dtd和schema作为该XML的说明文档,且不显示该属性
			doc.setXmlStandalone(true);
			// 创建TransformerFactory对象
			TransformerFactory tff = TransformerFactory.newInstance();
			// 创建Transformer对象
			Transformer tf = tff.newTransformer();
			//
			tf.setOutputProperty(OutputKeys.INDENT, "yes");
			// 输出到文件
			tf.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(xmlPath)));
		} catch (ParserConfigurationException | FileNotFoundException | TransformerException e) {
			log.error(e);
		}
	}

	private static Element createStuElement(Document doc, String no, String name, int age) {
		Element stuElem = doc.createElement("person");
		stuElem.setAttribute("no", no);
		//创建姓名节点
		Element nameElem = doc.createElement("name");
		nameElem.appendChild(doc.createTextNode(name));
		//创建年龄节点
		Element ageElem = doc.createElement("age");
		ageElem.appendChild(doc.createTextNode(age + ""));
		//将姓名、年龄节点添加到学生节点中并返回
		stuElem.appendChild(nameElem);
		stuElem.appendChild(ageElem);
		return stuElem;
	}
}

三、其他解析器

1. JDOM

JDOM是一个开源项目,它基于树型结构,利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。

Jdom可以和已有的XML技术如Simple API for XML (SAX)和 Document Object Model (DOM)相互协作。

实例>>

2.dom4j

dom4j是一个开源的Java的XML API,是jdom的升级品,用来读写XML文件的。dom4j是一个十分优秀的JavaXML API,具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术。

猜你喜欢

转载自marionette.iteye.com/blog/2388660