您现在的位置: 365建站网 > 365学习 > java解析xml的方法(DOM/SAX/JDOM/DOM4J)详解

java解析xml的方法(DOM/SAX/JDOM/DOM4J)详解

文章来源:365jz.com     点击数:236    更新时间:2018-05-29 11:20   参与评论
解析XML的方法详解

XML是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性、给数据集成与交互带来了极大的方便。XML在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。
  XML的解析方式分为四种:1、DOM解析;2、SAX解析;3、JDOM解析;4、DOM4J解析。其中前两种属于基础方法,是官方提供的平台无关的解析方式;后两种属于扩展方法,它们是在基础的方法上扩展出来的,只适用于java平台。

一:XML基础

XML是什么:

可扩展的标记语言

XML能干什么:

描述数据、存储数据、传输(交换)数据。

XML与HTML区别:

目的不一样

XML 被设计用来描述数据,其焦点是数据的内容。

HTML 被设计用来展示数据,其焦点是数据的外观。

HTML可以不关闭标签(即标签可以不成对出现),但XML必须关闭标签(即标签必须成对出现)。

HTML中的标签标识文本如何展示,而XML中的标签标识文本是什么含义(什么类型的文本)。

XML文档节点类型

u     文档(document)

u     元素(element)

u     属性(attribute)

u     文本(PCDATA--parsed character data)

u     注释(comment)

u     DOCTYPE :主要验证文档内容的正确性

u     实体(ENTITIES)

u     CDATA(character data)

XML语法

1、声明:<?xmlversion="1.0" encoding="UTF-8"?>

2、根节点:必须有一个根节点

3、标签:标签必须有结束且区分大小写,标签必须顺序嵌套

4、属性:必须引号引起值

5、空格会被保留,HTML空格最多保留一个

6、命名规则:命名必须见名知意

     a)名字可包含字母、数字以及其他的字符 

     b)名字不能以数字或者标点符号开始

     c)名字不能以字符“xml”(或者XML、Xml)开始

7、名字不能包含空格

8、 不应在 XML 元素名称中使用 ":" ,这是由于它用于命名空间(namespaces)的保留字。

9、标签优先于属性。

10、XML 命名空间可提供避免元素命名冲突的方法。

11、CDATA:字符数据,<![CDATA[字符数据]]> ,字符数据不进行转义

12、实体:&实体;

Xml约束

XML DTD 约束

DTD(DocType Definition 文档类型定义)的作用是定义 XML 文档的合法构建模块。

它使用一系列的合法元素来定义文档结构。用于约定XML格式。

1、DTD引用方式
  1、内部 <!DOCTYPE 根元素 [元素声明]>

例如:

<?xml version="1.0"encoding="UTF-8" standalone="yes"?>

<!DOCTYPE 书架 [

<!ELEMENT 书架 (书+)>

<!ELEMENT 书 (书名,作者,售价)>

<!ELEMENT 书名 (#PCDATA)>

<!ELEMENT 作者 (#PCDATA)>

<!ELEMENT 售价 (#PCDATA)>

]>

<书架>

<书>

        <书名>Java就业培训教程</书名>

        <作者>张孝祥</作者>

        <售价>39.00元</售价>

</书>

...

</书架>

  2、外部私有的 SYSTEM   一般是我们自己定义的,可能只是一个公司内部使用

<!DOCTYPE 根元素 SYSTEM "dtd文件位置">

例如:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE 书架 SYSTEM "book.dtd">

<书架>

   <书>

      <书名>java编程思想</书名>

      <作者>Brnee</作者>

      <售价>80</售价>

   </书>

</书架>

  3、外部公有的  PUBLIC   一般是一些标准,可能非常多的人用

 <!DOCTYPE 根元素 PUBLIC "命名空间""dtd文件位置">

首先根据“命名空间”去问环境要相应的dtd文件,如果有,直接提供,如果没有再根据dtd文件位置找。

 

      例如:<!DOCTYPE web-app PUBLIC

               "-//SunMicrosystems, Inc.//DTD Web Application 2.3//EN"

               "http://java.sun.com/dtd/web-app_2_3.dtd">

2、例子:
<?xml version="1.0"?>
<!DOCTYPE note [
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]>
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend</body>
</note>
3、参考文档:

点击打开链接

XML Schema 约束

XML Schema 是基于 XML 的 DTD 替代者。XML Schema 描述 XML 文档的结构。XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)。

DTD不是通过XML语法定义文档结构, 不能定义数据类型和限制Schema通过XML语法定义文档结构,可以定义数据类型和限制

约定XML格式

  • 定义可出现在文档中的元素
  • 定义可出现在文档中的属性
  • 定义哪个元素是子元素
  • 定义子元素的次序
  • 定义子元素的数目
  • 定义元素是否为空,或者是否可包含文本
  • 定义元素和属性的数据类型
  • 定义元素和属性的默认值以及固定值
1、为何使用Schema

XML Schema 是 DTD 的继任者

  • XML Schema 可针对未来的需求进行扩展
  • XML Schema 更完善,功能更强大
  • XML Schema 基于 XML 编写
  • XML Schema 支持数据类型和限制
  • XML Schema 支持命名空间
2、Schema引用方式

<users xmlns="命名空间"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="命名空间 Schema位置">

如何找Schema,和DTD一样,首先根据命名空间问环境要,找不到再根据Schema位置找。

3、例子:

<?xml version="1.0" encoding="UTF-8"?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
            <!--xs="http://www.w3.org/2001/XMLSchema" 声名了w3c的名称空间,方便下面调用 -->   
             
             targetNamespace="http://www.zhong.cn" 
                      elementFormDefault="qualified">     
<!-- 
    schema 是根元素 
     
    xmlns:xs="http://www.w3.org/2001/XMLSchema"                    
    指明了在schema中使用的元素和数据种类来自http://www.w3.org/2001/XMLSchema名称空间(namespace)。 
    它也指定了来自"http://www.w3.org/2001/XMLSchema"名称空间(namespace)的元素和数据种类必须带前缀“xs:”   
     
    targetNamespace="http://www.zhong.cn"(将全部元素绑定给这个名称空间) 
    暗示了由这份schema(shiporder, orderperson, shipto, ....)定义的元素来自"http://www.zhong.com"名称空间 
     
    xmlns="http://www.w3schools.com"  
    指明了默认名称空间(namespace)是http://www.w3schools.com.  
     
    elementFormDefault="qualified" (“unqualified”)将根节点绑定到名称空间 
        将所有元素绑定到名称空间 
  -->                   
                       
    <!--xs:element  指的是element这个元素来自于xs名称空间 -->                  
    <xs:element name="shiporder"> <!-- 定义一个元素 shiporder --> 
     <xs:complexType>             <!-- 类型是:复合类型(里面包含元素或者属性) --> 
      <xs:sequence>                   <!-- 元素要有顺序 --> 
       <xs:element name="orderperson" type="xs:string"/>          <!-- 定义一个元素 orderperson 类型为:字符串 --> 
       <xs:element name="shipto" minOccurs="1" maxOccurs="1"> <!-- 定义一个元素 shipto 最少出现1次,最多出现1次  --> 
        <xs:complexType> <!-- shipto元素也是复合类型 --> 
         <xs:sequence>   <!-- 元素要有顺序 --> 
          <xs:element name="name" type="xs:string"/> <!-- 在shipto元素中定义一个元素 name 类型为:字符串 --> 
          <xs:element name="address" type="xs:string"/> 
          <xs:element name="city" type="xs:string"/> 
          <xs:element name="country" type="xs:string"/> 
         </xs:sequence> 
        </xs:complexType> 
       </xs:element> 
       <xs:element name="item" maxOccurs="unbounded">  <!-- 在shiporder元素中定义一个元素 item 出现次数可以无限次 --> 
        <xs:complexType> 
         <xs:sequence> 
          <xs:element name="title" type="xs:string"/> 
          <xs:element name="note" type="xs:string" minOccurs="0"/> 
          <xs:element name="quantity" type="xs:positiveInteger"/> 
          <xs:element name="price" type="xs:decimal"/> 
         </xs:sequence> 
        </xs:complexType> 
       </xs:element> 
      </xs:sequence> 
      <xs:attribute name="orderid" type="xs:string" use="required"/> 
     </xs:complexType> 
    </xs:element>  
</xs:schema>  



二、Java解析XML


1. 介绍

1)DOM(JAXP Crimson解析器)
        DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。

  DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,DOM分析器还是有很广泛的使用价值的。

    优点:

      1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。

      2、解析过程中,树结构保存在内存中,方便修改。

    缺点:

      1、由于文件是一次性读取,所以对内存的耗费比较大。

      2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。

2)SAX

        SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。
  选择DOM还是选择SAX? 对于需要自己编写代码来处理XML文档的开发人员来说,  选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档,而SAX采用的事件模型。

  DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。

  SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。

    优点:

      1、采用事件驱动模式,对内存耗费比较小。

      2、适用于只处理XML文件中的数据时。

    缺点:

      1、编码比较麻烦。

      2、很难同时访问XML文件中的多处不同数据。

3)JDOM 

          JDOM的目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型,JDOM一直得到大力推广和促进。正在考虑通过“Java规范请求JSR-102”将它最终用作“Java标准扩展”。从2000年初就已经开始了JDOM开发。

  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许可证变体下发布的开放源码。

   特征:

      1、仅使用具体类,而不使用接口。

      2、API大量使用了Collections类。

4)DOM4J
            
        虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始,它就一直处于开发之中。

  为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出了更复杂的API的代价,但是它提供了比JDOM大得多的灵活性。

  在添加灵活性、XPath集成和对大文档处理的目标时,DOM4J的目标与JDOM是一样的:针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案,实现在本质上处理所有Java/XML问题的目标。在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。

  DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J。

     特征:

      1、JDOM的一种智能分支,它合并了许多超出基本XML文档表示的功能。

      2、它使用接口和抽象基本类方法。

      3、具有性能优异、灵活性好、功能强大和极端易用的特点。

      4、是一个开放源码的文件

2.. 比较

1)DOM4J性能最好,连Sun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J.

2)JDOM和DOM在性能测试时表现不佳,在测试10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM。虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础,因为它正式获得W3C推荐(与基于非标准的Java模型相对),所以在某些类型的项目中可能也需要它(如在JavaScript中使用DOM)。

3)SAX表现较好,这要依赖于它特定的解析方式-事件驱动。一个SAX检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。

3. 四种xml操作方式的基本使用方法

xml文件: 
 
<?xml version="1.0" encoding="utf-8" ?>  
<Result
   <VALUE
       <NO DATE="2005">A1</NO
       <ADDR>GZ</ADDR
   </VALUE
   <VALUE
       <NO DATE="2004">A2</NO
       <ADDR>XG</ADDR
  </VALUE
</Result
 
1)DOM 
 
import java.io.*; 
import java.util.*; 
import org.w3c.dom.*; 
import javax.xml.parsers.*; 
 
public class MyXMLReader{  
 public static void main(String arge[]){ 
 
  long lasting =System.currentTimeMillis();  
  try{   
   File f=new File("data_10k.xml");  
   DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();  
   DocumentBuilder builder=factory.newDocumentBuilder();  
   Document doc = builder.parse(f);  
   NodeList nl = doc.getElementsByTagName("VALUE");  
   for (int i=0;i<nl.getLength();i++){  
    System.out.print("车牌号码:" + doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue());  
    System.out.println("车主地址:" + doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue());  
   }  
  }catch(Exception e){  
   e.printStackTrace();  

 
2)SAX 
 
import org.xml.sax.*; 
import org.xml.sax.helpers.*; 
import javax.xml.parsers.*; 
 
public class MyXMLReader extends DefaultHandler { 
 
 java.util.Stack tags = new java.util.Stack();  
 public MyXMLReader() {  
  super(); 
   } 
 
 public static void main(String args[]) {  
  long lasting = System.currentTimeMillis();  
  try {  
   SAXParserFactory sf = SAXParserFactory.newInstance();  
   SAXParser sp = sf.newSAXParser();  
   MyXMLReader reader = new MyXMLReader();  
   sp.parse(new InputSource("data_10k.xml"), reader);  
  } catch (Exception e) {  
   e.printStackTrace();  
  } 
 
  System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒");}  
  public void characters(char ch[], int start, int length) throws SAXException {  
  String tag = (String) tags.peek();  
  if (tag.equals("NO")) {   
   System.out.print("车牌号码:" + new String(ch, start, length)); 
    } 
    if (tag.equals("ADDR")) {  
  System.out.println("地址:" + new String(ch, start, length)); 
    } 
   } 
 
  public void startElement(String uri,String localName,String qName,Attributes attrs) {  
  tags.push(qName);} 
}  
 
3) JDOM 
 
import java.io.*; 
import java.util.*; 
import org.jdom.*; 
import org.jdom.input.*; 
 
public class MyXMLReader { 
 
 public static void main(String arge[]) {  
  long lasting = System.currentTimeMillis();  
  try {  
   SAXBuilder builder = new SAXBuilder();   
   Document doc = builder.build(new File("data_10k.xml"));   
   Element foo = doc.getRootElement();   
   List allChildren = foo.getChildren();   
   for(int i=0;i<allChildren.size();i++) {   
    System.out.print("车牌号码:" + ((Element)allChildren.get(i)).getChild("NO").getText());  
    System.out.println("车主地址:" + ((Element)allChildren.get(i)).getChild("ADDR").getText());  
   }  
  } catch (Exception e) {  
   e.printStackTrace();  

 

 
4)DOM4J 
 
import java.io.*; 
import java.util.*; 
import org.dom4j.*; 
import org.dom4j.io.*; 
 
public class MyXMLReader { 
 
 public static void main(String arge[]) {  
  long lasting = System.currentTimeMillis();  
  try {  
   File f = new File("data_10k.xml");  
   SAXReader reader = new SAXReader();  
   Document doc = reader.read(f);  
   Element root = doc.getRootElement();  
   Element foo;  
   for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) {  
    foo = (Element) i.next();  
    System.out.print("车牌号码:" + foo.elementText("NO"));  
    System.out.println("车主地址:" + foo.elementText("ADDR"));  
   }  
  } catch (Exception e) {  
   e.printStackTrace();  
    }  





如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛


发表评论 (236人查看0条评论)
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
用户名: 验证码: 点击我更换图片
最新评论
------分隔线----------------------------