一、DOM(Document Object Model) 

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

优点: 

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

缺点: 

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

二、SAX(Simple API for XML) 

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

优点: 

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

缺点: 

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

三、JDOM(Java-based Document Object Model) 

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

优点: 

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

缺点: 

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

四、DOM4J(Document Object Model for Java) 

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

优点: 

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

缺点: 

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

五、StAX(Streaming API for XML) 

流模型中的拉模型分析方式。提供基于指针和基于迭代器两种方式的支持。 

优点: 

1、接口简单,使用方便。 
2、采用流模型分析方式,有较好的性能。

缺点: 

1、单向导航,不支持XPath,很难同时访问同一文档的不同部分。

==================================

本文最后给出一个stax的各种解析的例子。 在文档最后哦!

Java 6.0对XML支持的新特性有许多方面。比如StAX、针对XML-Web服务的Java架构(JAX-WS)2.0、针对XML绑定的API(JAXB)2.0、XML数字签名API,甚至还支持SQL:2003 'XML'数据类型。

#####

  WSDL的解析:wsdl4j   schema的解析:DOM、DOM4J、Apache Schema项目、Xerces等

  soapui

 jaxb :java对象与xml互相转换(JaxbContext)

#########

StAX是Streaming API for XML的缩写,是一种针对XML的流式拉分析API。关于对XML进行分析(或解析)的技术,大家一定都不陌生了。在Java 6.0之前,就已经有四种: 

  1. DOM:Document Object Model

  2. SAX:Simple API for XML

  3. JDOM:Java-based Document Object Model

  4. DOM4J:Document Object Model for Java

推分析拉分析。 

在程序中访问和操作XML文件一般有两种模型:DOM(文档对象模型)和流模型。它们的优缺点如下: 

引用

DOM优点:允许编辑和更新XML文档,可以随机访问文档中的数据,可以使用XPath(XML Path Language,是一种从XML文档中搜索节点的查询语言)查询。 

DOM缺点:需要一次性加载整个文档到内存中,对于大型文档,会造成性能问题。

引用

流模型优点:对XML文件的访问采用流的概念,在任何时候内存中只有当前节点,解决了DOM的性能问题。 

流模型缺点:是只读的,并且只能向前,不能在文档中执行向后导航操作。

流模型每次迭代XML文档中的一个节点,适合于处理较大的文档,所耗内存空间小。它有两种变体--“推”模型和“拉”模型。 

引用

推模型:就是我们常说的SAX,它是一种靠事件驱动的模型。当它每发现一个节点就引发一个事件,而我们需要编写这些事件的处理程序。这样的做法很麻烦,且不灵活。

引用

拉模型:在遍历文档时,会把感兴趣的部分从读取器中拉出,不需要引发事件,允许我们选择性地处理节点。这大大提高了灵活性,以及整体效率。

StAX就是一种拉分析式的XML解析技术。它也支持对XML文件的生成操作。

从一开始,JAXP(Java API for XML Processing)就提供了两种方法来处理XML:DOM和SAX。StAX是一种面向流的新方法,最终版本于2004年3月发布,并成为JAXP 1.4(包含在Java 6.0中)的一部分。StAX的实现使用了JWSDP(Java Web Services Development Pack)1.6,并结合了SJSXP(Sun Java System XML Streaming Parser,位于javax.xml.stream.*包中)。 

JWSDP是用来开发Web Services、Web应用程序以及Java应用(主要是XML处理)的开发包。它包含的Java API有: 

  • JAXP:Java API for XML Processing

  • JAXB:Java Architecture for XML Binding

  • JAX-RPC:Java API for XML-based Remote Procedure Calls

  • JAX-WS:Java API for XML Web Services

  • SAAJ:SOAP with Attachments API for Java

  • JAXR:Java API for XML Registries

  • Web Services Registry

JWSDP的早期版本中还包括: 

  • Java Servlet

  • JSP:JavaServer Pages

  • JSF:JavaServer Faces

现在,JWSDP已经被GlassFish所替代

StAX包括两套处理XML的API,分别提供了不同程度的抽象。它们是:基于指针的API和基于迭代器的API。

先来了解基于指针的API。它把XML作为一个标记(或事件)流来处理,应用程序可以检查解析器的状态,获得解析的上一个标记的信息,然后再处理下一个标记,依次类推。

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

  2. <company>  

  3.     <depart title="Develop Group">  

  4.         <user name="Tom" age="28" gender="male" >Manager</user>  

  5.         <user name="Lily" age="26" gender="female" />  

  6.     </depart>  

  7.     <depart title="Test Group">  

  8.         <user name="Frank" age="32" gender="male" >Team Leader</user>  

  9.         <user name="Bob" age="45" gender="male" />  

  10.         <user name="Kate" age="25" gender="female" />  

  11.     </depart>  

  12. </company>  

以让我们使用基于指针的API的接口是javax.xml.stream.XMLStreamReader(很遗憾,你不能直接实例化它),要得到它的实例,我们需要借助于javax.xml.stream.XMLInputFactory类。根据JAXP的传统风格,这里使用了抽象工厂(Abstract Factory)模式。如果你对这个模式很熟悉的话,就能够在脑海中想象出我们将要编写的代码的大致框架了。 

首先,获得一个XMLInputFactory的实例。方法是: 

XMLInputFactory factory = XMLInputFactory.newInstance(); 

  1. XMLInputFactory factory = XMLInputFactory.newFactory();  

接下来我们就可以创建XMLStreamReader实例了:

  1. try {  

  2.     XMLStreamReader reader = factory.createXMLStreamReader(new FileReader("users.xml"));  

  3. } catch (FileNotFoundException e) {  

  4.     e.printStackTrace();  

  5. } catch (XMLStreamException e) {  

  6.     e.printStackTrace();  

  7. }  

要遍历XML文档,需要用到XMLStreamReader的下面几个方法: 

Java代码  688A1C55D1A0B99D71C4C4166738769B_B500_90

  1. int getEventType();  

  2.   

  3. boolean hasNext() throws XMLStreamException;  

  4.   

  5. int next() throws XMLStreamException;

getEventType()方法返回XMLStreamConstants接口中定义的一个标记常量,表示当前指针所指向标记(或事件)的类型。根据当前事件类型的不同,应用程序可以做出不同的处理。标记常量的类型和含义如下: 

  1. START_DOCUMENT:文档的开始

  2. END_DOCUMENT:文档的结尾

  3. START_ELEMENT:元素的开始

  4. END_ELEMENT:元素的结尾

  5. PROCESSING_INSTRUCTION:处理指令

  6. CHARACTERS:字符(文本或空格)

  7. COMMENT:注释

  8. SPACE:可忽略的空格

  9. ENTITY_REFERENCE:实体的引用

  10. ATTRIBUTE:元素的属性

  11. DTD:DTD

  12. CDATA:CDATA块

  13. NAMESPACE:命名空间的声明

  14. NOTATION_DECLARATION:标记的声明

  15. ENTITY_DECLARATION:实体的声明

对systemId稍作说明,并简单解释一下它与publicId的区别。 

systemId和publicId是XML文档里DOCTYPE元素中经常出现的两个属性。它们都是对外部资源的引用,用以指明引用资源的地址。systemId是直接引用资源,publicId是间接定位外部资源。具体一点说是这样: 
引用

systemId:外部资源(大多是DTD文件)的URI。比如本地文件file:///user/dtd/users.dtd或者网络某个地址的文件http://www.w3.org/dtd/users.dtd。

引用

publicId:相当于一个名字,这个名字代表了一个外部资源。比如,我们规定"W3C HTML 4.0.1"这个字符串对应"http://www.w3.org/dtd/users.dtd"这个资源。那么,publicId="W3C HTML 4.0.1"和systemId="http://www.w3.org/dtd/users.dtd"的作用就是一样的。

我们的测试代码如下:

  1. /** 

  2.  * 列出所有用户 

  3.  *  

  4.  * @author zangweiren 2010-4-17 

  5.  *  

  6.  */  

  7. public class ListUsers {  

  8.     // 获得解析器  

  9.     public static XMLStreamReader getStreamReader() {  

  10.         String xmlFile = ListUsers.class.getResource("/").getFile()  

  11.                 + "users.xml";  

  12.         XMLInputFactory factory = XMLInputFactory.newFactory();  

  13.         try {  

  14.             XMLStreamReader reader = factory  

  15.                     .createXMLStreamReader(new FileReader(xmlFile));  

  16.             return reader;  

  17.         } catch (FileNotFoundException e) {  

  18.             e.printStackTrace();  

  19.         } catch (XMLStreamException e) {  

  20.             e.printStackTrace();  

  21.         }  

  22.         return null;  

  23.     }  

  24.   

  25.     // 列出所有用户名称  

  26.     public static void listNames() {  

  27.         XMLStreamReader reader = ListUsers.getStreamReader();  

  28.         // 遍历XML文档  

  29.         try {  

  30.             while (reader.hasNext()) {  

  31.                 int event = reader.next();  

  32.                 // 如果是元素的开始  

  33.                 if (event == XMLStreamConstants.START_ELEMENT) {  

  34.                     // 列出所有用户名称  

  35.                     if ("user".equalsIgnoreCase(reader.getLocalName())) {  

  36.                         System.out.println("Name:"  

  37.                                 + reader.getAttributeValue(null, "name"));  

  38.                     }  

  39.                 }  

  40.             }  

  41.             reader.close();  

  42.         } catch (XMLStreamException e) {  

  43.             e.printStackTrace();  

  44.         }  

  45.     }  

  46.   

  47.     public static void main(String[] args) {  

  48.         ListUsers.listNames();  

  49.     }  

  50. }  

上面我们介绍了基于指针的StAX API。这种方式尽管效率高,但是没有提供XML结构的抽象,因此是一种低层API。 

较为高级的基于迭代器的API允许应用程序把XML作为一系列事件对象来处理,每个对象和应用程序交换XML结构的一部分。应用程序只需要确定解析事件的类型,将其转换成对应的具体类型,然后利用其方法获得属于该事件对象的信息。 

StAX中基于迭代器的API是一种面向对象的方式,这也是它与基于指针的API的最大区别。它通过将事件转变为对象,让应用程序可以用面向对象的方式处理它们,这有利于模块化和不同组件之间的代码重用。 

事件迭代器API的主要接口是javax.xml.stream.XMLEventReader和javax.xml.stream.events.XMLEvent。XMLEventReader和XMLStreamReader相比要简单的多,这是因为关于解析事件的所有信息都封装在了事件对象(XMLEvent)中。 

=========================================

stax例子:

/**

 * 利用java Stax API处理xml

 */

@Test

public void testStax1(){

//本测试为stax的基于光标的xml处理

XMLInputFactory factory = XMLInputFactory.newInstance();

InputStream is = null ;

is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");

try {

XMLStreamReader reader = factory.createXMLStreamReader(is);

while(reader.hasNext()){

int type = reader.next();

//判断节点类型(是否为 开始节点或结束节点或者文本节点)

if(type == XMLStreamConstants.START_ELEMENT){

System.out.println(reader.getName());//文本节点没有name

//输出节点的属性(此处输出book的id)

String name = reader.getName().toString();

if(name.equals("book")){

System.out.println(reader.getAttributeName(0)+" == "+reader.getAttributeValue(0));

}

}else if(type == XMLStreamConstants.CHARACTERS){//文本节点

System.out.println(reader.getText().trim());

}else if(type == XMLStreamConstants.END_ELEMENT){

System.out.println(reader.getName());

}

}

} catch (XMLStreamException e) {

e.printStackTrace();

}

}

@Test

public void testStax2(){

//本测试为stax的基于迭代的方式(XmlEventReader)

XMLInputFactory factory = XMLInputFactory.newInstance();

InputStream is = null ;

is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");

try {

//通过XMLEventReader来判断节点的类型

XMLEventReader reader = factory.createXMLEventReader(is);

while(reader.hasNext()){

XMLEvent event = reader.nextEvent();

//

if(event.isStartElement()){

String name = event.asStartElement().getName().toString();

if(name.equals("book")){

System.out.println(reader.getElementText());

}

}

}

} catch (XMLStreamException e) {

e.printStackTrace();

}

}

@Test

public void testStax3(){

//本测试为stax的基于过滤器方式:该方式可以有效地过滤掉不需要操作的节点,效率较高。

XMLInputFactory factory = XMLInputFactory.newInstance();

InputStream is = null ;

is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");

try {

//通过XMLEventReader来判断节点的类型

XMLEventReader reader = factory.createFilteredReader(factory.createXMLEventReader(is), new EventFilter() {

public boolean accept(XMLEvent event) {

if(event.isStartElement()){

return true ;

}

return false;

}

});

while(reader.hasNext()){

XMLEvent event = reader.nextEvent();

//

if(event.isStartElement()){

String name = event.asStartElement().getName().toString();

if(name.equals("book")){

System.out.println(reader.getElementText());

}

}

}

} catch (XMLStreamException e) {

e.printStackTrace();

}

}

@Test

public void testXpath(){

//通过xpath处理xml

InputStream is = null ;

try {

is = TestStax.class.getClassLoader().getResourceAsStream("book.xml");

DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();

Document doc = db.parse(is);

XPath xpath = XPathFactory.newInstance().newXPath();//创建xpath

xpath.evaluate("//book[@id='bk102 ']", doc);//从源为doc的xml中找符合第一个参数(xpath表达式)的节点信息

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

@Test

public void testStaxWriteAndModify(){

//通过stax写xml 或者修改xml

InputStream is = null ;

try {

XMLStreamWriter xml = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);

xml.writeStartDocument("GBK","1.0");

xml.writeEndDocument();

xml.writeStartElement("person");

xml.writeStartElement("name");

xml.writeCharacters("tom");

xml.writeEndElement();//注意 每一个节点都要关闭,包括文本节点

xml.writeEndElement();

xml.flush();

xml.close();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}