java通过DOM操作xml

本贴最后更新于 3019 天前,其中的信息可能已经渤澥桑田

XML

XML (eXtensible Markup Language), 可扩展标记语言,发明之初是为了取代 HTML,但在使用过程中,开发者发现这种规范的语言格式,在数据传输方面有着明显的优势。
这里只将 XML 作为一种数据交换格式。
比如说 java 语言本身的 javaBean 数据,在程序内使用没有问题,但是如果涉及到与其他语言进行交互,则会出现很多问题。所以通过 XML 进行数据传输通信,可以拥有更好的跨平台性和可移植性,并且让底层数据预备了可读性。
本篇文章的重点在于介绍如果通过 java DOM 对 XML 文件进行解析与操作。

dom

DOM 是 W3C 处理 XML 的标准 API,多种语言都实现了该标准,java 对 dom 的实现在 org.w3c.dom 包内。很多工具类都是在此基础上进行了封装和扩充,如 jdom、dom4j 等,这里使用原生实现来完成对 xml 文档的基本操作。
DOM 的实现原理是将 XML 作为树结构全部读入内存,再进行操作。好处是简单快捷,可以修改结构和数据,而造成的隐患则是是在读取大型 XML 文件时,可能会造成过多的内存占用。

代码

读取解析 xml 文件

需要读取的 xml 文件如下,传递了商品订单信息,包括商品名、价格、购买数量。通过程序读取数据,并计算出订单总价格。
因为本次重点在于 xml 的解析操作,所以价格直接用 float 类型处理。如果是生产环境,一定要使用 BigDecimal 操作,避免 float 的精度问题!!

<?xml version="1.0" encoding="UTF-8" ?>
<shopping>
	<goods>
		<name>品名1</name>
		<price>3</price>
		<number>4</number>
	</goods>
	<goods>
		<name>品名2</name>
		<price>1.2</price>
		<number>3</number>
	</goods>
</shopping>

java 读取 XML 代码

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;

public class XmlParser {
	
	DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	
	public Document parseDoc(String filePath) {
		Document document = null;
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			document = builder.parse(new File(filePath));
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return document;
	}
	
	public static void main(String[] args) {
		XmlParser parser = new XmlParser();
		Document document = parser.parseDoc("D://shopping.xml");
		Element rootElement = document.getDocumentElement();
		List<Goods> goodsList = new ArrayList<Goods>();
		NodeList goodsNodeList = rootElement.getElementsByTagName("goods");
		for (int i = 0; i < goodsNodeList.getLength(); i++) {
			Element child = (Element) goodsNodeList.item(i);
			Goods goods = new Goods(child);
			goodsList.add(goods);
		}
		
//        NodeList goodsNodeList = rootElement.getChildNodes();
//        for (int i = 0; i < goodsNodeList.getLength(); i++) {
//            Node node = goodsNodeList.item(i);
//            if (node.getNodeType() == Node.ELEMENT_NODE) {
//                Element child = (Element) node;
//                Goods goods = new Goods(child);
//                goodsList.add(goods);
//            }
//        }
		float total = 0;
		int sum = 0;
		for (Goods goods : goodsList) {
			total += goods.getTotal();
			sum += goods.getNumber();
		}
		System.out.println(total);
		System.out.println(sum);
	}
	
	static class Goods {
		private float price;
		private int number;
		public Goods(Element element) {
			this.price = Float.parseFloat(element.getElementsByTagName("price").item(0).getTextContent());
			this.number = Integer.parseInt(element.getElementsByTagName("number").item(0).getTextContent());
		}
		public float getTotal(){
			return this.price * this.number;
		}
		public int getNumber(){
			return number;
		}
	}
}

node 和 element 的关系

element 一定是 node 但是 node 不一定是 element,node 可能是元素节点、属性节点、文本节点,而 element 表示包含开始标签和结束标签的完整元素。
所以上面的代码中 用

NodeList goodsNodeList = rootElement.getElementsByTagName("goods");

获取了 NodeList,可以直接转型为 Element: Element child = (Element) node;
如果获取的是 node 节点

NodeList goodsNodeList = rootElement.getChildNodes();

则必须在循环中增加判断 if (node.getNodeType() == Node.ELEMENT_NODE) {} 判断当前节点是否为 Element 元素。

生成 xml 文件

将统计后的订单信息以 xml 格式输出,生成文件格式如下

<?xml version="1.0" encoding="utf-8"?>
<order>
	<total>15.6</total>
	<sums>7</sums>
</order>

生成 xml 的操作和读取的顺序类似,先创建 rootElement,然后添加 childElement,再将 rootElement 放到 document 中,最后通过 io 输出 xml 文件到指定路径。
代码如下:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
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 XmlParser {
	
	DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
	TransformerFactory transformerFactory = TransformerFactory.newInstance();
	
	public Document parseDoc(String filePath) {
		Document document = null;
		try {
			DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
			document = builder.parse(new File(filePath));
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return document;
	}
	
	public void generateXml(String filePath, Document document){
		DOMSource source = new DOMSource(document);
		Transformer transformer = createtransformer();
		PrintWriter pw = null;
		try {
			pw = new PrintWriter(new FileOutputStream(filePath));
			StreamResult result = new StreamResult(pw);
			transformer.transform(source, result);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (TransformerConfigurationException e1) {
			e1.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		} finally {
			pw.close();
		}
	}
	
	public Document createDoc() {
		Document document = null;
		try {
			DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
			document = builder.newDocument();
			document.setXmlStandalone(true);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		return document;
	}
	
	public Transformer createtransformer(){
		Transformer transformer = null;
		try {
			transformer = transformerFactory.newTransformer();
			//default former
//            transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
			transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		}
		return transformer;
	}
	
	public static void main(String[] args) {
		XmlParser parser = new XmlParser();
		Document document = parser.parseDoc("D://shopping.xml");
		Element rootElement = document.getDocumentElement();
		List<Goods> goodsList = new ArrayList<Goods>();
		NodeList goodsNodeList = rootElement.getElementsByTagName("goods");
		for (int i = 0; i < goodsNodeList.getLength(); i++) {
			Element child = (Element) goodsNodeList.item(i);
			Goods goods = new Goods(child);
			goodsList.add(goods);
		}
		float total = 0;
		int sum = 0;
		for (Goods goods : goodsList) {
			total += goods.getTotal();
			sum += goods.getNumber();
		}
		Document orderDocument = parser.createDoc();
		Order order = new Order(total, sum);
		Element orderElement = order.getElement(orderDocument);
		orderDocument.appendChild(orderElement);
		
		parser.generateXml("D://order.xml", orderDocument);

	}
	
	static class Order {
		private float total = 0;
		private int   sum   = 0;
		
		public Order(float total, int sum) {
			this.total = total;
			this.sum = sum;
		}
		
		public Element getElement(Document document) {
			Element rootElement = document.createElement("order");
			
			Element totalElement = document.createElement("total");
			totalElement.setTextContent(String.valueOf(this.total));
			rootElement.appendChild(totalElement);
			
			Element sumElement = document.createElement("sum");
			sumElement.setTextContent(String.valueOf(this.sum));
			rootElement.appendChild(sumElement);
			
			return rootElement;
		}
		
	}
	
	static class Goods {
		private float price;
		private int   number;
		
		public Goods(Element element) {
			this.price = Float.parseFloat(element.getElementsByTagName("price").item(0).getTextContent());
			this.number = Integer.parseInt(element.getElementsByTagName("number").item(0).getTextContent());
		}
		
		public float getTotal() {
			return this.price * this.number;
		}
		
		public int getNumber() {
			return number;
		}
	}
}

standalone

这里有一个小坑 就是生成的 xml 中有一个属性为 standalone="no"
standalone 表示是否为独立文件,也就是说是否依赖于其他外部文件,如果为 yes,则表示为不依赖其他外部文件的独立文件,默认为 yes。
但是生成之后的 standalone="no",不符合预期,并且

transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");

设置格式之后 standalone="no"仍然为 no。这时需要设置 document 中的 setXmlStandalone 属性,

document.setXmlStandalone(true);

再次输出,可以去掉 standalone 属性。

结语

理解 xml 的结构之后,和 dom 的树形结构后,无论是使用原生支持还是通过第三方类库去操作 xml 文件,都可以很容易的上手。
and 我喜欢用 json

打赏 100 积分后可见
100 积分 • 1 打赏
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3165 引用 • 8206 回帖 • 1 关注
  • dom
    7 引用 • 7 回帖
  • XML
    28 引用 • 59 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...