热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Java中使用DOM和SAX解析XML文件的方法示例

这篇文章主要介绍了Java中使用DOM和SAX解析XML文件的方法示例,通过实例文章中最后也给出了一些对比结论,需要的朋友可以参考下

dom4j介绍
  dom4j的项目地址:http://sourceforge.net/projects/dom4j/?source=directory

  dom4j是一个简单的开源库,用于处理XML、 XPath和XSLT,它基于Java平台,使用Java的集合框架,全面集成了DOM,SAX和JAXP。

 

dom4j的使用
  下载了dom4j项目之后,解压缩,将其jar包(我的当前版本叫做dom4j-1.6.1.jar)加入class path下面。

  (Properties->Java Build Path -> Add External JARs...)。

  之后就可以使用其提供的API进行编程。

 

程序实例1
  第一个程序,用Java代码生成xml文档,代码如下:

package com.example.xml.dom4j;

import java.io.FileOutputStream;
import java.io.FileWriter;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

/**
 * dom4j框架学习 使用dom4j框架创建xml文档并输出保存
 * 
 */
public class Dom4JTest1
{

  public static void main(String[] args) throws Exception
  {
    // 第一种方式:创建文档,并创建根元素
    // 创建文档:使用了一个Helper类
    Document document = DocumentHelper.createDocument();

    // 创建根节点并添加进文档
    Element root = DocumentHelper.createElement("student");
    document.setRootElement(root);

    // 第二种方式:创建文档并设置文档的根元素节点
    Element root2 = DocumentHelper.createElement("student");
    Document document2 = DocumentHelper.createDocument(root2);

    // 添加属性
    root2.addAttribute("name", "zhangsan");
    // 添加子节点:add之后就返回这个元素
    Element helloElement = root2.addElement("hello");
    Element worldElement = root2.addElement("world");

    helloElement.setText("hello Text");
    worldElement.setText("world text");

    // 输出
    // 输出到控制台
    XMLWriter xmlWriter = new XMLWriter();
    xmlWriter.write(document);

    // 输出到文件
    // 格式
    OutputFormat format = new OutputFormat("  ", true);// 设置缩进为4个空格,并且另起一行为true
    XMLWriter xmlWriter2 = new XMLWriter(
        new FileOutputStream("student.xml"), format);
    xmlWriter2.write(document2);

    // 另一种输出方式,记得要调用flush()方法,否则输出的文件中显示空白
    XMLWriter xmlWriter3 = new XMLWriter(new FileWriter("student2.xml"),
        format);
    xmlWriter3.write(document2);
    xmlWriter3.flush();
    // close()方法也可以

  }
}

 

  程序Console输出:

<&#63;xml version="1.0" encoding="UTF-8"&#63;>

  生成的一个xml文档:

<&#63;xml version="1.0" encoding="UTF-8"&#63;>


  hello Text
  world text


 

程序实例2
  程序实例2,读入xml文档并分析,将其内容输出。

  首先,待分析的文档如下:

<&#63;xml version="1.0" encoding="UTF-8"&#63;>


  hello Text1
  hello Text2
  hello Text3
  world text1
  world text2
  world text3

 

package com.example.xml.dom4j;

import java.io.File;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.DOMReader;
import org.dom4j.io.SAXReader;

/**
 * dom4j框架学习: 读取并解析xml
 * 
 * 
 */
public class Dom4JTest2
{
  public static void main(String[] args) throws Exception
  {
    SAXReader saxReader = new SAXReader();

    Document document = saxReader.read(new File("students.xml"));

    // 获取根元素
    Element root = document.getRootElement();
    System.out.println("Root: " + root.getName());

    // 获取所有子元素
    List childList = root.elements();
    System.out.println("total child count: " + childList.size());

    // 获取特定名称的子元素
    List childList2 = root.elements("hello");
    System.out.println("hello child: " + childList2.size());

    // 获取名字为指定名称的第一个子元素
    Element firstWorldElement = root.element("world");
    // 输出其属性
    System.out.println("first World Attr: "
        + firstWorldElement.attribute(0).getName() + "="
        + firstWorldElement.attributeValue("name"));

    System.out.println("迭代输出-----------------------");
    // 迭代输出
    for (Iterator iter = root.elementIterator(); iter.hasNext();)
    {
      Element e = (Element) iter.next();
      System.out.println(e.attributeValue("name"));

    }

    System.out.println("用DOMReader-----------------------");
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    // 注意要用完整类名
    org.w3c.dom.Document document2 = db.parse(new File("students.xml "));

    DOMReader domReader = new DOMReader();

    // 将JAXP的Document转换为dom4j的Document
    Document document3 = domReader.read(document2);

    Element rootElement = document3.getRootElement();

    System.out.println("Root: " + rootElement.getName());

  }

}


  代码运行后输出:

Root: students
total child count: 6
hello child: 3
first World Attr: name=wangwu
迭代输出-----------------------
lisi
lisi2
lisi3
wangwu
wangwu2
null
用DOMReader-----------------------
Root: students


SAX解析XML
下面是SAX实现实体解析的步骤
//下面使用XMLReader 来解析
(一)第一步:新建一个工厂类SAXParserFactory,代码如下:
SAXParserFactory factory = SAXParserFactory.newInstance();
(二)第二步:让工厂类产生一个SAX的解析类SAXParser,代码如下:
SAXParser parser = factory.newSAXParser();
(三)第三步:从SAXPsrser中得到一个XMLReader实例,代码如下:
XMLReader reader = parser.getXMLReader();
(四)第四步:把自己写的handler注册到XMLReader中,一般最重要的就是ContentHandler,代码如下:
reader.setContentHandler(this);
(五)第五步:将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始,代码如下:
reader.parse(new InputSource(is));
 
 
//下面使用SAXParser来解析
(一)第一步:新建一个工厂类SAXParserFactory,代码如下:
SAXParserFactory factory = SAXParserFactory.newInstance();
(二)第二步:让工厂类产生一个SAX的解析类SAXParser,代码如下:
SAXParser parser = factory.newSAXParser();
(三)第三步:将一个xml文档或者资源变成一个java可以处理的InputStream流后,解析正式开始,代码如下:
parser.parse(is,this);
估计大家都看到了ContentHandler ,下面具体的讲下
解析开始之前,需要向XMLReader/SAXParser 注册一个ContentHandler,也就是相当于一个事件监听器,在ContentHandler中定义了很多方法
//设置一个可以定位文档内容事件发生位置的定位器对象
public void setDocumentLocator(Locator locator)
 
//用于处理文档解析开始事件
public void startDocument()throws SAXException
 
//处理元素开始事件,从参数中可以获得元素所在名称空间的uri,元素名称,属性类表等信息
public void startElement(String namespacesURI , String localName , String qName , Attributes atts) throws SAXException
 
//处理元素结束事件,从参数中可以获得元素所在名称空间的uri,元素名称等信息
public void endElement(String namespacesURI , String localName , String qName) throws SAXException
 
//处理元素的字符内容,从参数中可以获得内容
public void characters(char[] ch , int start , int length)  throws SAXException
顺便介绍下XMLReader中的方法。
//注册处理XML文档解析事件ContentHandler
public void setContentHandler(ContentHandler handler)
 
//开始解析一个XML文档
public void parse(InputSorce input) throws SAXException

大概的讲的差不多了  接下来开始讲解解析的步骤
我们还是用上一章的代码
首先 我们创建一个Person类  用来存储用户的信息

package com.example.demo; 
 
import java.io.Serializable; 
 
public class Person implements Serializable { 
 
  /** 
   * 
   */ 
  private static final long serialVersiOnUID= 1L; 
  private String _id; 
  private String _name; 
  private String _age; 
 
  public String get_id() { 
    return _id; 
  } 
 
  public void set_id(String _id) { 
    this._id = _id; 
  } 
 
  public String get_name() { 
    return _name; 
  } 
 
  public void set_name(String _name) { 
    this._name = _name; 
  } 
 
  public String get_age() { 
    return _age; 
  } 
 
  public void set_age(String _age) { 
    this._age = _age; 
  } 
} 

接下来  我们要实现一个ContentHandler 用来解析XML
实现一个ContentHandler 一般需要下面几个步骤
1、声明一个类,继承DefaultHandler。DefaultHandler是一个基类,这个类里面简单实现了一个ContentHandler。我们只需要重写里面的方法即可。
2、重写 startDocument() 和 endDocument(),一般将正式解析之前的初始化放到startDocument()里面,收尾的工作放到endDocument()里面。
3、重写startElement(),XML解析器遇到XML里面的tag时就会调用这个函数。经常在这个函数内是通过对localName的值进行判断而操作一些数据。
4、重写characters()方法,这是一个回调方法。解析器执行完startElement()后,解析节点的内容后就会执行这个方法,并且参数ch[]就是节点的内容。
5、重写endElement()方法,这个方法与startElement()相对应,解析完一个tag节点后,执行这个方法,解析一个tag后,调用这个处理还原和清除相关信息
首先   新建一个类 继承DefaultHandler 并重写以下几个方法

public class SAX_parserXML extends DefaultHandler { 
 
  /** 
   * 当开始解析xml文件的声明的时候就会触发这个事件, 可以做一些初始化的工作 
   * */ 
  @Override 
  public void startDocument() throws SAXException { 
    // TODO Auto-generated method stub 
    super.startDocument(); 
     
  } 
 
  /** 
   * 当开始解析元素的开始标签的时候,就会触发这个事件 
   * */ 
  @Override 
  public void startElement(String uri, String localName, String qName, 
      Attributes attributes) throws SAXException { 
    // TODO Auto-generated method stub 
    super.startElement(uri, localName, qName, attributes); 
  } 
 
  /** 
   * 当读到文本元素的时候要触发这个事件. 
   * */ 
  @Override 
  public void characters(char[] ch, int start, int length) 
      throws SAXException { 
    // TODO Auto-generated method stub 
    super.characters(ch, start, length); 
  } 
 
  /** 
   * 当读到结束标签的时候 就会触发这个事件 
   * */ 
  @Override 
  public void endElement(String uri, String localName, String qName) 
      throws SAXException { 
    // TODO Auto-generated method stub 
    super.endElement(uri, localName, qName); 
  } 
 
} 

首先  我们创建一个list  用来保存解析出来的person数据

List persons; 

但是?在哪里初始化呢?我们可以在startDocument()里面初始化,因为当开始解析xml文件的声明的时候就会触发这个事件所以放在这里比较合适

/** 
 * 当开始解析xml文件的声明的时候就会触发这个事件, 可以做一些初始化的工作 
 * */ 
@Override 
public void startDocument() throws SAXException { 
  // TODO Auto-generated method stub 
  super.startDocument(); 
  // 初始化list 
  persOns= new ArrayList(); 
} 

接下来  就要开始解析了  

/** 
   * 当开始解析元素的开始标签的时候,就会触发这个事件 
   * */ 
  @Override 
  public void startElement(String uri, String localName, String qName, 
      Attributes attributes) throws SAXException { 
    // TODO Auto-generated method stub 
    super.startElement(uri, localName, qName, attributes); 
 
    // 如果读到是person标签 开始存储 
    if (localName.equals("person")) { 
      person = new Person(); 
      person.set_id(attributes.getValue("id")); 
    } 
    curNode = localName; 
  } 

 上面的代码中  localName表示当前解析到的元素名

//步骤 
//1.判断是否是person元素 
//2.创建新的Person对象 
//3.获取id 添加到Person对象中 
curNode 用来保存当前的元素名 在characters中会使用到
/** 
   * 当读到文本元素的时候要触发这个事件. 
   * */ 
  @Override 
  public void characters(char[] ch, int start, int length) 
      throws SAXException { 
    // TODO Auto-generated method stub 
    super.characters(ch, start, length); 
 
    if (person != null) { 
      //取出目前元素对应的值 
      String txt = new String(ch, start, length); 
      //判断元素是否是name 
      if (curNode.equals("name")) { 
        //将取出的值添加到person对象 
        person.set_name(txt); 
      } else if (curNode.equals("age")) { 
        person.set_age(txt); 
      } 
    } 
  } 

接下来是介绍标签结束的时候需要做的事情

/** 
 * 当读到结束标签的时候 就会触发这个事件 
 * */ 
@Override 
public void endElement(String uri, String localName, String qName) 
    throws SAXException { 
  // TODO Auto-generated method stub 
  super.endElement(uri, localName, qName); 
 
  // 如果是 并且person不为空,添加到list 
  if (localName.equals("person") && person != null) { 
    persons.add(person); 
    person = null; 
  } 
 
  curNode = ""; 
} 

解析的事情结束了  大概流程就是
1.一个元素开始时    会调用startElement方法
2.接下来会调用到characters方法,可以用来获取元素的值
3.一个元素结束时    会调用到endElement方法
解析结束之后  我们需要写一个方法  用来获取解析后保存的list

public List ReadXML(InputStream is) { 
 
    SAXParserFactory factory = SAXParserFactory.newInstance(); 
    try { 
      SAXParser parser = factory.newSAXParser(); 
 
      // 第一种方法 
      // parser.parse(is, this); 
 
      // 第二种方法 
      XMLReader reader = parser.getXMLReader(); 
      reader.setContentHandler(this); 
      reader.parse(new InputSource(is)); 
 
    } catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
    } 
 
    return persons; 
  } 

上面的代码就不解释了   只要将inputStream对象传入  就可以解析出内容
看完了代码,我来给出完整的代码

package com.example.demo.Utils; 
 
import java.io.InputStream; 
import java.util.ArrayList; 
import java.util.List; 
 
import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 
 
import org.xml.sax.Attributes; 
import org.xml.sax.InputSource; 
import org.xml.sax.SAXException; 
import org.xml.sax.XMLReader; 
import org.xml.sax.helpers.DefaultHandler; 
 
import com.example.demo.Person; 
 
public class SAX_parserXML extends DefaultHandler { 
 
  List persons; 
  Person person; 
  // 当前节点 
  String curNode; 
 
  public List ReadXML(InputStream is) { 
 
    SAXParserFactory factory = SAXParserFactory.newInstance(); 
    try { 
      SAXParser parser = factory.newSAXParser(); 
 
      // 第一种方法 
      // parser.parse(is, this); 
 
      // 第二种方法 
      XMLReader reader = parser.getXMLReader(); 
      reader.setContentHandler(this); 
      reader.parse(new InputSource(is)); 
 
    } catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
    } 
 
    return persons; 
  } 
 
  /** 
   * 当开始解析xml文件的声明的时候就会触发这个事件, 可以做一些初始化的工作 
   * */ 
  @Override 
  public void startDocument() throws SAXException { 
    // TODO Auto-generated method stub 
    super.startDocument(); 
    // 初始化list 
    persOns= new ArrayList(); 
  } 
 
  /** 
   * 当开始解析元素的开始标签的时候,就会触发这个事件 
   * */ 
  @Override 
  public void startElement(String uri, String localName, String qName, 
      Attributes attributes) throws SAXException { 
    // TODO Auto-generated method stub 
    super.startElement(uri, localName, qName, attributes); 
 
    // 如果读到是person标签 开始存储 
    if (localName.equals("person")) { 
      person = new Person(); 
      person.set_id(attributes.getValue("id")); 
    } 
    curNode = localName; 
  } 
 
  /** 
   * 当读到文本元素的时候要触发这个事件. 
   * */ 
  @Override 
  public void characters(char[] ch, int start, int length) 
      throws SAXException { 
    // TODO Auto-generated method stub 
    super.characters(ch, start, length); 
 
    if (person != null) { 
      // 取出目前元素对应的值 
      String txt = new String(ch, start, length); 
      // 判断元素是否是name 
      if (curNode.equals("name")) { 
        // 将取出的值添加到person对象 
        person.set_name(txt); 
      } else if (curNode.equals("age")) { 
        person.set_age(txt); 
      } 
    } 
  } 
 
  /** 
   * 当读到结束标签的时候 就会触发这个事件 
   * */ 
  @Override 
  public void endElement(String uri, String localName, String qName) 
      throws SAXException { 
    // TODO Auto-generated method stub 
    super.endElement(uri, localName, qName); 
 
    // 如果是person结尾 并且person不为空,添加到list 
    if (localName.equals("person") && person != null) { 
      persons.add(person); 
      person = null; 
    } 
 
    curNode = ""; 
  } 
 
} 

 写个方法调用下这个类

List persOns= new SAX_parserXML().ReadXML(is); 
      StringBuffer buffer = new StringBuffer(); 
      for (int i = 0; i 

 如果你看到下面的界面  说明解析成功了~

201511985306423.png (332×102)

小结:

DOM(文件对象模型)解析:解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以根据DOM接口来操作这个树结构了。 
 
  优点:整个文档读入内存,方便操作:支持修改、删除和重现排列等多种功能。 
 
  缺点:将整个文档读入内存中,保留了过多的不需要的节点,浪费内存和空间。 
 
  使用场合:一旦读入文档,还需要多次对文档进行操作,并且在硬件资源充足的情况下(内存,CPU)。 
 
为了解决DOM解析存在的问题,就出现了SAX解析。其特点为: 
 
  优点:不用实现调入整个文档,占用资源少。尤其在嵌入式环境中,如android,极力推荐使用SAX解析。 
 
  缺点:不像DOM解析一样将文档长期驻留在内存中,数据不是持久的。如果事件过后没有保存数据,数据就会丢失。 
 
  使用场合:机器有性能限制


推荐阅读
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 本文详细介绍如何使用arm-eabi-gdb调试Android平台上的C/C++程序。通过具体步骤和实用技巧,帮助开发者更高效地进行调试工作。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文将详细介绍如何使用剪映应用中的镜像功能,帮助用户轻松实现视频的镜像效果。通过简单的步骤,您可以快速掌握这一实用技巧。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 本文介绍了一款用于自动化部署 Linux 服务的 Bash 脚本。该脚本不仅涵盖了基本的文件复制和目录创建,还处理了系统服务的配置和启动,确保在多种 Linux 发行版上都能顺利运行。 ... [详细]
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
author-avatar
手机用户2502937013
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有