XML解析 - KelovpString

/ 0评 / 0

    在连续吹了好几天的JSON,但最终还是低头了。太多原始开发和老旧的API依旧使用,W3C这一大腿还真是抱的的爽,虽然吐槽其笨重但是必要的解析还是要会。我们基本上在Java当中有三种办法可以解决这次的问题 。

DOM解析

    在Java当中DOM 是 W3C 处理 XML 的标准 API,它是许多其它与 XML 处理相关的标准的基础,不仅是 Java,其它诸如 Javascript,PHP,MS .NET 等等语言都实现了该标准, 成为了应用最为广泛的 XML 处理方式。当然,为了能提供更多更加强大的功能,Java 对于 DOM 直接扩展工具类有很多,比如很多 Java 程序员耳熟能详的 JDOM,DOM4J 等等, 它们基本上属于对 DOM 接口功能的扩充,保留了很多 DOM API 的特性。所以一般意义来讲一个具有通行标准的方法值得去关注。

    处理方式:
    将XML整个作为类似树结构的方式读入内存中以便操作及解析,因此支持应用程序对XML数据的内容和结构进行修改,但是同时由于其需要在处理开始时将整个 XML 文件读入到内存中去进行分析,因此其在解析大数据量的 XML 文件时会遇到类似于内存泄露以及程序崩溃的风险。根据DOM,XML被文档视为一种树结构。这种树结构被称为节点树。文档中的每个成分都是一个节点(Node)。可通过这棵树访问所有节点。可以修改或删除它们的内容,也可以创建新的元素。

    上面也有说到是按照节点处理:XML 文档的 documentElement 属性是根节点。而旗下就有更多东西了,而在Java当中拥有众多方法来帮你完成解析大部分的工作,在解析过程当中,我们规定NodeType为1则是元素 ,属性 2 ,文本 3 ,注释 8 ,文档 9 这样来定义,而更其NodeName更是只对应相应类型的名字。
    适用范围:
    小型 XML 文件解析、需要全解析或者大部分解析 XML、需要修改 XML 树内容以生成自己的对象模型

    在Java当中的使用方法:

    

	//javax.xml.parsers 包中的 DoumentBuilder 和DocumentBuilderFactory 用于解析 XML 文档生成对应的 DOM Document 对象。
		DocumentBuilderFactory dbf = 
				DocumentBuilderFactory.newInstance();
		//创建文档创建器
		DocumentBuilder builder = dbf.newDocumentBuilder();
		//创建Dom文档
		Document dom = builder.parse(new File(fileName));

		//javax.xml.transform.dom 和 javax.xml.transform.stream 包中 DOMSource 类和 StreamSource 类,用于将更新后的 DOM 文档写入 XML 文件
		DOMSource source = new DOMSource(d);
		Transformer trans = TransformerFactory.newInstance()
				.newTransformer();
		
		StreamResult result = new StreamResult(
				new FileOutputStream(new File(fileName)));
		trans.transform(source, result);

     这样我们可以用DOM来解析:

	public static void DomXMl() throws Exception {
                Map<String, Double> tknine = new HashMap<String, Double>();
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = factory.newDocumentBuilder();
		Document doc = db.parse(new File("src/user.xml"));
		Element root = doc.getDocumentElement();
		NodeList cls = root.getChildNodes();
		for (int i = 0; i < cls.getLength(); i++) {
			Node node = cls.item(i);
			if (node.getNodeType() == 1) {
				NamedNodeMap map = node.getAttributes();
				NodeList tk = node.getChildNodes();
				for (int j = 0; j < tk.getLength(); j++) {
					Node tkj = tk.item(j);
					Node tks = map.item(j);
					if (!tknine.containsKey(tks.getNodeValue())) {
						tknine.put(tks.getNodeValue(),
								Double.parseDouble(tkj.getTextContent()));
					} else if (tknine.containsKey(tks.getNodeValue())) {
						double ks = tknine.get(tks.getNodeValue());
						tknine.put(tks.getNodeValue(),
								Double.parseDouble(tkj.getTextContent()) + ks);
					}
				}
			}
		}
		for (String ks : tknine.keySet()) {
			System.out.println(ks + "消费了:" + tknine.get(ks));
		}
	}

 利用DOM进行写入:

public static void WriteByDom() throws Exception {
		Document doc = DocumentBuilderFactory.newInstance()
				.newDocumentBuilder().newDocument();
		Element root = doc.createElement("records");
		for (String ks : tknine.keySet()) {
			Element record = doc.createElement("record");
			Element name = doc.createElement("name");
			Element price = doc.createElement("price");
			name.setTextContent(ks);
			price.setTextContent("" + tknine.get(ks));
			root.appendChild(record);
			record.appendChild(name);
			record.appendChild(price);
		}
		doc.appendChild(root);
		TransformerFactory tff = TransformerFactory.newInstance();
		Transformer tf = tff.newTransformer();
		tf.setOutputProperty(OutputKeys.INDENT, "yes");// huanhang
		tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");//滑稽 控制格式输出
		DOMSource sourse = new DOMSource(doc);
		Result result = new StreamResult(new File("src/writeByDom.xml"));
		tf.transform(sourse, result);
	}

被操作的xml:

<?xml version="1.0" encoding="UTF-8"?>
<users>
	<user name ="tom">26.5</user>
	<user name ="jack">126.5</user>
	<user name ="tom">29.5</user>
	<user name ="terry">66.5</user>
	<user name ="marry">29.5</user>
	<user name ="ody">95.5</user>
	<user name ="jack">96.5</user>
	<user name ="tom">46.5</user>
</users>

JDOM解析

    一款蛮针对Java的解析办法(创作者就是Java开发者),它简化了DOM更迅速,利用大量接口尤其collections,熟悉Java语言的话是要比DOM好用几倍的(这里说下特点吧)

     JDOM 与 DOM 主要有两方面不同。首先,JDOM 仅使用具体类而不使用接口。这在某些方面简化了 API,但是也限制了灵活性。第二,API 大量使用了 Collections 类,简化了那些已经熟悉这些类的 Java 开发者的使用。
    JDOM 文档声明其目的是“使用 20%(或更少)的精力解决 80%(或更多)Java/XML 问题”(根据学习曲线假定为 20%)。JDOM 对于大多数 Java/XML 应用程序来说当然是有用的,并且大多数开发者发现 API 比 DOM 容易理解得多。JDOM 还包括对程序行为的相当广泛检查以防止用户做任何在 XML 中无意义的事。然而,它仍需要您充分理解 XML 以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习 DOM 或 JDOM 接口都更有意义的工作。
    JDOM 自身不包含解析器。它通常使用 SAX2 解析器来解析和验证输入 XML 文档(尽管它还可以将以前构造的 DOM 表示作为输入)。它包含一些转换器以将 JDOM 表示输出成 SAX2 事件流、DOM 模型或 XML 文本文档。JDOM 是在 Apache 许可证变体下发布的开放源码。(段落转自:http://blog.csdn.net/shijinupc/article/details/7653945,里面描述了各种解析办法之间的不同和优缺点)

DOM4j解析

    DOM4J 是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,是jdom的升级品,大量使用接口(个人感觉最op//同样都是小文件的话)在开源项目当中大量使用。其解析办法(依旧针对以上的xml文件):

public static void SaxXMl() throws Exception {
		SAXReader reader = new SAXReader();
		Document dom = reader.read(new File("src/user.xml"));
		Element root = dom.getRootElement();
		List<Element> child = root.elements();
		for (Element e : child) {
			List<Attribute> rs = e.attributes();
			for (Attribute aks : rs)
				if (!tknine.containsKey(aks.getValue())) {
					tknine.put(aks.getValue(),
							Double.parseDouble(e.getTextTrim()));
				} else if (tknine.containsKey(aks.getValue())) {
					double ks = tknine.get(aks.getValue());
					tknine.put(aks.getValue(),
							Double.parseDouble(e.getTextTrim()) + ks);
				}
		}
		for (String ks : tknine.keySet()) {
			System.out.println(ks + "消费了:" + tknine.get(ks));
		}
	}

而写入在这里:

public static void WriteByDom4j() throws Exception {
		Document doc = DocumentFactory.getInstance().createDocument();
		Element root = doc.addElement("records");
		for (String ks : tknine.keySet()) {
			Element record = root.addElement("record");
			Element name = record.addElement("name");
			Element price = record.addElement("price");
			name.setText(ks);
			price.setText("" + tknine.get(ks));
		}
		OutputFormat of = new OutputFormat();
		of.setNewlines(true);
		of.setIndent("\t");
		FileWriter fw = new FileWriter("src/writerByDom4J.xml");
		XMLWriter writer = new XMLWriter(fw, of);
		writer.write(doc);
		fw.close();
		writer.close();
	}

SAX解析

    通过类似于流解析的技术,通读整个 XML文档树,通过事件处理器来响应程序员对于 XML数据解析的需求(所以说sax是基于事件处理的)。由于其不需要将整个XML文档读入内存当中,它对系统资源的节省是十分显而易见的,它在一些需要处理大型XML文档以及性能要求较高的场合有起了十分重要的作用
    适用范围:大型 XML 文件解析、只需要部分解析或者只想取得部分 XML 树内容、有 XPath 查询需求、有自己生成特定 XML 树对象模型的需求 

    显然面对大文件时SAX的优势一显无疑,事件处理给予SAX更强的能力,但是编码困难就不吐槽了(对于新手极不友好

综述

    以上有四种解析方法,在小文档情况下还值得考虑使用 DOM 和 JDOM。另外,DOM 仍是一个非常好的选择。DOM 实现广泛应用于多种编程语言。它还是许多其它与 XML 相关的标准的基础,在某些类型的项目中可能也需要它(如在 javascript 中使用 DOM)。SAX解析大文件较强,这要依赖于它特定的解析方式。一个 SAX 检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。最后在这四种中强烈推DOM4j(今天编程过程愉悦且人性)。溜啦=-=


发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注