xml常用四种解析方式优缺点的分析×××××

时间:2023-03-08 22:18:37
xml常用四种解析方式优缺点的分析×××××

最近用得到xml的解析方式,于是就翻了翻自己的笔记同时从网上查找了资料,自己在前人的基础上总结了下,贴出来大家分享下。

首先介绍一下xml语言:

可扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。

xml的语法:

XML 分为两部分:头信息,主体信息

头信息是用来描述 XML 的一些属性,例如:版本,编码等,还可以提供 XML 显示的样式,和 dtd 编写格式。

主体信息中包含的是 XML 的具体数据。

头信息的语法:

<?xml version =”1.0” encoding =”GBK” ?>

其中 version 是必须加的,而 encoding 可以不写,则默认编码是 ISO8859-1 ,不支持中文。

除了这个功能外,头信息还可以进行编写格式的规定,通过 dtd 或 xsd 文件。

头信息还支持样式表的导入,允许通过样式表控制 XML 的显示。

这样可以使用 XML+ CSS 完成页面的显示,通过这种形式完成 MVC 中的 View 层:

优点:代码的安全性很高,可以很容易的替换模板。

缺点:开发成本太高

主体信息 就是由三种节点组成的,节点之间存在父与子的关系,注意的点:

一个节点只能有一个父节点,如果没有父节点,该节点称为根节点。

一个节点可以有多个子节点。只有元素节点可以拥有子节点。

元素节点的标记必须成对出现,或直接结束。

特殊字符必须转义。依据字符所处的位置是否对 XML 格式造成影响来决定是否进行转义

根节点只能有一个

xml常用的四种解析方式:

1)DOM(Document Object Model)

文档对象模型分析方式。以层次结构(类似于树型)来组织节点和信息片段,映射XML文档的结构,允许获取和操作文档的任意部分。是W3C的官方标准。

优点:
1、允许应用程序对数据和结构做出更改。
2、访问是双向的,可以在任何时候在树中上下导航,获取和操作任意部分的数据。

缺点:
1、通常需要加载整个XML文档来构造层次结构,消耗资源大

2)SAX(Simple API for XML)

流模型中的推模型分析方式。通过事件驱动,每发现一个节点就引发一个事件,通过回调方法完成解析工作,解析XML文档的逻辑需要应用程序完成。

优点:
1、不需要等待所有数据都被处理,分析就能立即开始。
2、只在读取数据时检查数据,不需要保存在内存中。
3、可以在某个条件得到满足时停止解析,不必解析整个文档。
4、效率和性能较高,能解析大于系统内存的文档。

缺点:
1、需要应用程序自己负责TAG的处理逻辑(例如维护父/子关系等),使用麻烦。
2、单向导航,很难同时访问同一文档的不同部分数据,不支持XPath。

3)JDOM(Java-based Document Object Model)

Java特定的文档对象模型。自身不包含解析器,使用SAX。

优点:
1、使用具体类而不是接口,简化了DOM的API。
2、大量使用了Java集合类,方便了Java开发人员。

缺点:
1、没有较好的灵活性。
2、性能较差。

4)DOM4J(Document Object Model for Java)

简单易用,采用Java集合框架,并完全支持DOM、SAX和JAXP。

优点:
1、大量使用了Java集合类,方便Java开发人员,同时提供一些提高性能的替代方法。
2、支持XPath。
3、有很好的性能。

缺点:
1、大量使用了接口,API较为复杂。

下面把四种解析方式的代码贴一下,首先是DOM方式

  1. public class DOMXml {
  2. public static void createXML(String outputPath) {
  3. // 建立Document对象
  4. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  5. // 创建DocumentBuilder
  6. try {
  7. DocumentBuilder db = factory.newDocumentBuilder();
  8. // 创建Document,建立新的对象
  9. Document doc = db.newDocument();
  10. // 建立各个节点
  11. // 元素节点
  12. Element allplus = doc.createElement("allplus");
  13. Element areaplus = doc.createElement("areaplus");
  14. Element id = doc.createElement("id");
  15. Element title = doc.createElement("title");
  16. // 创建文本节点
  17. Text idText = doc.createTextNode("1");
  18. Text titleText = doc.createTextNode("123");
  19. // 配置父子节点的关系
  20. id.appendChild(idText);
  21. title.appendChild(titleText);
  22. areaplus.appendChild(id);
  23. areaplus.appendChild(title);
  24. allplus.appendChild(areaplus);
  25. // allplus是根节点,应该设置为doc的子节点
  26. doc.appendChild(allplus);
  27. // 执行保存操作
  28. TransformerFactory tf = TransformerFactory.newInstance();
  29. Transformer t = tf.newTransformer();
  30. // 包装要保存的doc
  31. DOMSource source = new DOMSource(doc);
  32. // 设置输出流
  33. StreamResult sr = new StreamResult(new File(outputPath));
  34. // 设置输出的属性
  35. t.setOutputProperty("encoding", "UTF-8");
  36. // t.setOutputProperty("version", "1.0");
  37. // 输出
  38. t.transform(source, sr);
  39. } catch (DOMException e) {
  40. // TODO Auto-generated catch block
  41. e.printStackTrace();
  42. } catch (ParserConfigurationException e) {
  43. // TODO Auto-generated catch block
  44. e.printStackTrace();
  45. } catch (Exception e) {
  46. // TODO Auto-generated catch block
  47. e.printStackTrace();
  48. }
  49. }
  50. public static void parseXML(String xmlPath) {
  51. /*优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;
  52. * 缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;
  53. * 使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。
  54. * 10M文档导致内存溢出
  55. */
  56. // 建立Document对象
  57. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  58. // 创建DocumentBuilder
  59. try {
  60. DocumentBuilder db = factory.newDocumentBuilder();
  61. // 创建Document,形成树型结构
  62. Document doc = db.parse(new File(xmlPath));
  63. // 先取得所有的data
  64. NodeList datas = doc.getElementsByTagName("data");
  65. // 循环取得每个data
  66. for (int i = 0; i < datas.getLength(); i++) {
  67. Node data = datas.item(i);
  68. // 由于直接取得第一个和最后一个不符合要求,因此使用取得全部子节点的方式
  69. NodeList actorInfos = data.getChildNodes();
  70. for (int j = 0; j < actorInfos.getLength(); j++) {
  71. Node actorInfo = actorInfos.item(j);
  72. NodeList allChild = actorInfo.getChildNodes();
  73. for (int t = 0; t < allChild.getLength(); t++) {
  74. //判断节点
  75. Node child = allChild.item(t);
  76. if (child.getNodeType() == Node.ELEMENT_NODE) {
  77. if (child.getNodeName().equals("id")) {
  78. //判断是否有孩子节点,然后再取值
  79. if(child.hasChildNodes()) {
  80. System.out.println(child.getFirstChild().getNodeValue());
  81. }
  82. }
  83. if (child.getNodeName().equals("name")) {
  84. //判断是否有孩子节点,然后再取值
  85. if(child.hasChildNodes()) {
  86. System.out.println(child.getFirstChild().getNodeValue());
  87. }
  88. }
  89. }
  90. }
  91. }
  92. }
  93. } catch (ParserConfigurationException e) {
  94. // TODO Auto-generated catch block
  95. e.printStackTrace();
  96. } catch (SAXException e) {
  97. // TODO Auto-generated catch block
  98. e.printStackTrace();
  99. } catch (IOException e) {
  100. // TODO Auto-generated catch block
  101. e.printStackTrace();
  102. }
  103. }
  104. public static void main(String[] args) {
  105. parseXML("D:/actor_info.xml");
  106. createXML("d:/fxb.xml");
  107. }

SAX解析方式

  1. public class SAXXml extends DefaultHandler {
  2. private List<Book> books = null;
  3. private Book book = null;
  4. private String preTag = null;// 作用是记录解析时的上一个节点名称
  5. public List<Book> getBooks(InputStream xmlStream) throws Exception {
  6. SAXParserFactory factory = SAXParserFactory.newInstance();
  7. SAXParser parser = factory.newSAXParser();
  8. SAXXml handler = new SAXXml();
  9. parser.parse(xmlStream, handler);
  10. return handler.getBooks();
  11. }
  12. public List<Book> getBooks() {
  13. return books;
  14. }
  15. @Override
  16. public void startDocument() throws SAXException {
  17. books = new ArrayList<Book>();
  18. }
  19. @Override
  20. public void startElement(String uri, String localName, String qName,
  21. Attributes attributes) throws SAXException {
  22. if ("book".equals(qName)) {
  23. book = new Book();
  24. book.setId(Integer.parseInt(attributes.getValue(0)));
  25. }
  26. preTag = qName;// 将正在解析的节点名称赋给preTag
  27. }
  28. @Override
  29. public void endElement(String uri, String localName, String qName)
  30. throws SAXException {
  31. if ("book".equals(qName)) {
  32. books.add(book);
  33. book = null;
  34. }
  35. preTag = null;
  36. /**
  37. * 当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法
  38. * ,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是book,当文档顺序读到图
  39. * 中标记4的位置时,会执行characters(char[] ch, int start, int
  40. * length)这个方法,而characters(....)方
  41. * 法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给book,这不是我们想要的。
  42. */
  43. }
  44. @Override
  45. public void characters(char[] ch, int start, int length)
  46. throws SAXException {
  47. if (preTag != null) {
  48. String content = new String(ch, start, length);
  49. if ("name".equals(preTag)) {
  50. book.setName(content);
  51. } else if ("price".equals(preTag)) {
  52. book.setPrice(Float.parseFloat(content));
  53. }
  54. }
  55. }
  56. public static void main(String args[]) {
  57. SAXXml handler = new SAXXml();
  58. // 定义SUN自带解析对象
  59. SAXParser parser;
  60. try {
  61. parser = SAXParserFactory.newInstance().newSAXParser();
  62. parser.parse(new File("D:/book.xml"), handler);
  63. } catch (ParserConfigurationException e) {
  64. // TODO Auto-generated catch block
  65. e.printStackTrace();
  66. } catch (SAXException e) {
  67. // TODO Auto-generated catch block
  68. e.printStackTrace();
  69. } catch (IOException e) {
  70. // TODO Auto-generated catch block
  71. e.printStackTrace();
  72. }
  73. List<Book> books = handler.getBooks();
  74. for (Book book : books) {
  75. System.out.println(book.toString());
  76. }
  77. }

JDOM解析方式

  1. public class JDOMXml {
  2. public static void createXML(String outputPath) {
  3. // 先建立Document对象
  4. Document doc = new Document();
  5. // 建立元素节点
  6. Element allplus = new Element("allplus");
  7. try {
  8. // 建立多个Element
  9. Element areaplus = new Element("areaplus");
  10. Element id = new Element("id");
  11. Element title = new Element("title");
  12. // 设置节点内容
  13. id.addContent("id");
  14. title.addContent("title");
  15. // 设置父子节点关系
  16. areaplus.addContent(id);
  17. areaplus.addContent(title);
  18. allplus.addContent(areaplus);
  19. // 设置根节点
  20. doc.setRootElement(allplus);
  21. // 使用IO流操作
  22. FileWriter writer = new FileWriter(new File(outputPath));
  23. // 定义输出对象
  24. XMLOutputter outputter = new XMLOutputter();
  25. // 设置编码
  26. outputter.setEncoding("UTF-8");
  27. // 输出
  28. outputter.output(doc, writer);
  29. writer.close();
  30. } catch (Exception e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. }
  35. public static void parseXML(String xmlPath) {
  36. /*
  37. * 10M文档导致内存溢出
  38. */
  39. //完成解析功能。
  40. SAXBuilder builder = new SAXBuilder();
  41. try {
  42. Document doc = builder.build(new File(xmlPath));
  43. // 开始解析,取得根节点
  44. Element data = doc.getRootElement();
  45. // 取得所有的areaplus
  46. List<Element> actorInfos = data.getChildren("actor_info");
  47. if(actorInfos != null && actorInfos.size()>0) {
  48. for(Element actorInfo:actorInfos) {
  49. Element id = actorInfo.getChild("id");
  50. Element name = actorInfo.getChild("name");
  51. System.out.println(id.getTextTrim() + " --- " + name.getTextTrim());
  52. }
  53. }
  54. } catch (JDOMException e) {
  55. e.printStackTrace();
  56. } catch (IOException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. public static void main(String[] args) {
  61. parseXML("D:/actor_info.xml");
  62. createXML("d:/fdfdsf.xml");
  63. }

DOM4J解析方式

  1. package com.fxb.test;
  2. import java.io.File;
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. import java.io.Writer;
  6. import java.util.Iterator;
  7. import org.dom4j.Document;
  8. import org.dom4j.DocumentException;
  9. import org.dom4j.DocumentHelper;
  10. import org.dom4j.Element;
  11. import org.dom4j.io.SAXReader;
  12. import org.dom4j.io.XMLWriter;
  13. /**
  14. *
  15. * @author hongliang.dinghl Dom4j 生成XML文档与解析XML文档
  16. */
  17. public class DOM4JXml {
  18. public void createXml(String fileName) {
  19. Document document = DocumentHelper.createDocument();
  20. Element employees = document.addElement("data");
  21. Element employee = employees.addElement("actor_info");
  22. Element id = employee.addElement("id");
  23. id.setText("1");
  24. Element name = employee.addElement("name");
  25. name.setText("你好");
  26. Element message = employee.addElement("message");
  27. message.setText("你好吗");
  28. Element pic = employee.addElement("pic");
  29. pic.setText("123");
  30. Element sex = employee.addElement("sex");
  31. pic.setText("男");
  32. Element birthday = employee.addElement("birthday");
  33. pic.setText("19881212");
  34. try {
  35. Writer fileWriter = new FileWriter(fileName);
  36. XMLWriter xmlWriter = new XMLWriter(fileWriter);
  37. xmlWriter.write(document);
  38. xmlWriter.close();
  39. } catch (IOException e) {
  40. System.out.println(e.getMessage());
  41. }
  42. }
  43. public void parserXml(String fileName) {
  44. File inputXml = new File(fileName);
  45. SAXReader saxReader = new SAXReader();
  46. try {
  47. Document document = saxReader.read(inputXml);
  48. Element data = document.getRootElement();
  49. for (Iterator i = data.elementIterator(); i.hasNext();) {
  50. Element actorInfo = (Element) i.next();
  51. //System.out.println(employee.getName() + "->" + employee.getText());
  52. for (Iterator j = actorInfo.elementIterator(); j.hasNext();) {
  53. Element child = (Element) j.next();
  54. System.out.println(child.getName() + ":" + child.getText());
  55. }
  56. System.out.println("=================");
  57. }
  58. } catch (DocumentException e) {
  59. System.out.println(e.getMessage());
  60. }
  61. }
  62. public static void main(String args[]) {
  63. DOM4JXml dom = new DOM4JXml();
  64. //dom.parserXml("d:/actor_info.xml");
  65. dom.createXml("d:/fxb.xml");
  66. }
  67. }
4 
2 
分享到:  
评论
1 楼 hecal 2012-08-11  
god,兄弟你的代码有个bug.
在你的SAX解析方式里,有一个小bug.其他的没看。

50.    @Override  
51.    public void characters(char[] ch, int start, int length)  
52.            throws SAXException {  
53.        if (preTag != null) {  
54.            String content = new String(ch, start, length);  
55.            if ("name".equals(preTag)) {  
56.                book.setName(book.getName() + content);  
57.            } else if ("price".equals(preTag)) {  
58.                book.setPrice(Float.parseFloat(content));  
59.            }  
60.        }  
61.    }

原因:当name是很长的文章的时候,就被切断了,结果出错了。

http://lewis-fxb.iteye.com/blog/1243298