在连续吹了好几天的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(今天编程过程愉悦且人性)。溜啦=-=