stax解析xml详解

2012/03/13 3242点热度 0人点赞 0条评论

StAX  The Streaming API for XML (StAX)  基于流的XML编程接口

1、StAX是什么?

从一开始,Java API for XML Processing (JAXP)就提供了两种方法来处理 XML:

1、  文档对象模型(DOM-DocumentObject Model文档对象模型)方法是用标准的对象模型表示 XML 文档。

2、  Simple API for XML (SAX简单API for XML) 方法使用应用程序提供的事件处理程序来处理 XML。JSR-173提出了一种面向流的新方法:Streaming API for XML (StAX)。其最终版本于 2004 年3 月发布,并成为了 JAXP 1.4(将包含在即将发布的 Java 6 中)的一部分。

3、  如其名称所暗示的那样,StAX 把重点放在。实际上,StAX 与其他方法的区别就在于应用程序能够把 XML 作为一个事件流来处理。将 XML 作为一组事件来处理的想法并不新颖(事实上 SAX 已经提出来了),但不同之处在于 StAX 允许应用程序代码把这些事件逐个pull出来,而不用提供在解析器方便时从解析器中接收事件的处理程序。

2、推分析 VS 拉分析

拉分析较于推分析具有以下优点:

1、  在拉分析中,事件是由分析应用程序生成的,因此将分析规则提供到客户端而不是分析器。

2、  拉分析的代码更加简单,且它比推分析有更少的库。

3、  可以同时处理多个文档。

4、  允许你过虑或是跳过部分事件的处理。

3、StAX VS SAX

  1、StAX是拉分析,SAX是推分析。

  2、StAX比SAX更加容易编程。

  3、StAX即可读文档也可以写文档。而SAX只可以读取文档。

4、StAX的API编程接口

StAX编程接口都位于javax.xml.stream包中。StAX提供了两种方式的编程接口,它们是:

1、  Iterator API

  它的特点是:方便易用、实现简单。

  主要类是:XMLEventReader和XMLEventWriter。

2、  Crusor API

  它的特点是:运行速度快,底层编程。

  主要类是:XMLStreamReader和XMLStreamWriter。

5、Iterator API编程接口

 1、XMLEvent

       提供一系列的属性方法,判断文件是开始、结束。

       StartDocument文档的开始

       StartElement、EndElement(元素的开始与结束)、Characters(字符串节点元素)

       EntityReference 实体引用

       Comment注释、EndDocument文档结束,DTD约束

       Attribute属性,Namespace命名空间

 2、XMLEventReader

    提供遍历XML文档的能力。它的源代码如下:    

public interface XMLEventReader extends Iterator {
   public XMLEvent nextEvent() throws XMLStreamException;
   public boolean hasNext();
   public XMLEvent peek() throws XMLStreamException;
   public String getElementText() throws XMLStreamException;
   public XMLEvent nextTag() throws XMLStreamException;
   ...
}

    可见,它就是一个遍历器。

 3、  XMLEventWriter

   XMLEventWriter提供向写XML的功能。

   它的源代码如下:

public interface XMLEventWriter extends XMLEventConsumer {
   public voidflush()throws XMLStreamException;
   public void close() throws XMLStreamException;
   public void add(XMLEvent event) throws XMLStreamException;
   public void add(XMLEventReader reader) throws XMLStreamException;
   ...
}

6、StAX的工厂类

XMLInputFactory、XMLOutputFactory、XMLEventFactory是StAX的工厂类,通过这些类可以获取reader、writer和event的实例。

7、XMLEventReader接口

 以下示例XMLEventReader遍历文档中的数据部分:

 准备XML文档如下:

<?xmlversion="1.0"encoding="UTF-8"?>
<users>
    <userid="U001">
       <name>Jack</name>
       <age>23</age>
    </user>
    <userid="U002">
       <name>张三</name>
       <age>18</age>
    </user>
</users>

 要求读取上面的ID、姓名和年龄信息:

 示例代码如下:

package cn.stax.iterator;
import java.io.FileReader;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.junit.Test;
/**
 * XMLEventReader读取XML文档
 */
public class XMLEventReaderDemo {
    @Test
    public void readDemo() throws Exception{
       //初始化工厂类以创建出XMLEventReader对象
       XMLInputFactory factory =    
              XMLInputFactory.newFactory();
       //通过读取XML文件创建XMLEventReader
       XMLEventReader reader=      
              factory.createXMLEventReader(
                     new FileReader("./src/users.xml"));
       //判断是否还有下一个元素
       while(reader.hasNext()){
           //获取元素对象XMLEvent
           XMLEvent en= reader.nextEvent();    
           //判断是否是元素的开始
           if(en.isStartElement()){        
              StartElement se = en.asStartElement();
              //只获取非命名空间的部分
              if(se.getName().getLocalPart().equals("user")){
                  System.err.println("ID:"+
                            se.getAttributeByName(new QName("id"))
                            .getValue());
              }
              //判断是否是姓名元素
              if(se.getName().getLocalPart().equals("name")){
                  //获取姓名元素里面的文本元素
                  XMLEvent cha= reader.nextEvent();
                  //转成字符串输出
                  System.err.println("Name:"+cha.asCharacters());
              }
              if(se.getName().getLocalPart().equals("age")){
                  XMLEvent cha= reader.nextEvent();
                  System.err.println("Age:"+cha.asCharacters());
                  System.err.println("--------------------------");
              }
           }
       }
       reader.close();
    }
}

运行的结果如下:

   ID:U001

   Name:Jack

   Age:23

   -----------------------------------------

   ID:U002

   Name:张三

   Age:18

8、XMLEventWriter接口

此接口提供写XML文档的功能,笔者不建议使用XMLEventWriter生成XML文档,以下仅供生成参考,因为Stax生来就是为了快速读取文档的,而不是生成文档的。

本示例最终在生成以下格式的XML文档:

<?xmlversion="1.0"encoding="UTF-8"?>
<users>
    <userid="U001">
       <name>Jack在中国北京</name>
    </user>
</users>

完整的源代码如下:

package cn.stax.iterator;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.junit.Test;
public class XMLEventWriterDemo {
    @Test
    public void testWriter() throws Exception{
       //声明静态工厂
       XMLOutputFactory factory = 
              XMLOutputFactory.newFactory();
       //创建XMLEventWriter对象
       XMLEventWriter writer = 
              factory.createXMLEventWriter(new FileWriter("./src/res.xml"));
       //声明XMLEvent工厂
       XMLEventFactory ef = XMLEventFactory.newInstance();
       //声明文档开始即:<?xml version="1.0" encoding="UTF-8"?>
       XMLEvent event = ef.createStartDocument("UTF-8","1.0");
       writer.add(event);
       //声明开始标签<user,注意后面没有那个>,只在遇到EndElement时才会有>.
       StartElement se = ef.createStartElement(new QName("users"),null,null);
       writer.add(se);
       //给user元素声明一个属性
       Attribute att =ef.createAttribute("id", "UX001");
       List<Attribute> list = new ArrayList<Attribute>();
       list.add(att);
       //声明user元素,且带有属性
       se = 
ef.createStartElement(new QName("user"),list.iterator(),null);
       writer.add(se);
       //在user子元素内部声明一个name元素再
       se = ef.createStartElement(new QName("name"),null,null);
       writer.add(se);
       //声明一个文本元素
       Characters ce  =ef.createCharacters("Jack在中国北京");
       writer.add(ce);
       //以下再从内向外依次声明结束元素
       EndElement ee = null;
       ee = ef.createEndElement(new QName("name"),null);
       writer.add(ee);
                   
       ee = ef.createEndElement(new QName("user"),null);
       writer.add(ee);
                   
       ee = ef.createEndElement(new QName("users"),null);
       writer.add(ee);
       writer.flush();
       writer.close();
                   
    }
}

在了解了元素了嵌套关系以后,可以重复声明写入多个元素。就不再赘述。

9、Cursor API编程接口

CursorAPI提供两个实现实现对XML的读写,XMLStreamReader负责仅向前的读取数据。XMLStreamWriter可快速且简单的写出一个XML文档。

10、XMLStreamReader接口

以下代码,仍然读取上例中的XML文件:

package cn.itcast.cursor;
import java.io.FileReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import org.junit.Test;
public class XMLStreamReaderDemo {
    @Test
    public void readDemo() throws Exception{
       //声明工厂类对象
       XMLInputFactory factory = 
              XMLInputFactory.newFactory();
       //从工厂类中构造出XMLStreamReader对象
       XMLStreamReader reader = 
           factory.createXMLStreamReader(new FileReader("./src/users.xml"));
       //判断是否存在下一个元素
       while(reader.hasNext()){
           intelement= reader.next();
           //判断是否是元素的开始
           if(element==XMLStreamConstants.START_ELEMENT){
              //获取元素短名称
              String name = reader.getLocalName();
              if(name.equals("user")){
                  //ID属性
                  String id = reader.getAttributeValue(0);
                  System.err.println("ID:"+id);
              }
              if(name.equals("name")){
                  //name元素里面的值
                  name = reader.getElementText();
                  System.err.println("NAME:"+name);
              }
              if(name.equals("age")){
                  name = reader.getElementText();
                  System.err.println("AGE:"+name);
                  System.err.println("-----------------");
              }
           }
       }
       reader.close();
    }
}

通过上面的示例可以看出,使用CursorAPI可以更加简洁的读取XML文档中关心的部分。

11、XMLStreamWriter

使用XMLStreamWriter可以快速的生成一个XML文档。在生成元素时,必须要按元素的嵌套关系生成且结束。

package cn.itcast.cursor;
import java.io.FileWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
importorg.junit.Test;
public class XMLStreamWriterDemo {
    @Test
    public void writerDemo() throws Exception{
       //声明输出工厂
       XMLOutputFactory factory = 
              XMLOutputFactory.newFactory();
       //声明writer对象
       XMLStreamWriter writer = 
           factory.createXMLStreamWriter(new FileWriter("./src/res2.xml"));
       //文档开始即:<?xml...?>
       writer.writeStartDocument("UTF-8", "1.0");
       //根元素<users
       writer.writeStartElement("users");
       writer.writeStartElement("user");
       writer.writeAttribute("id","U00A1");//设置属性
        writer.writeStartElement("name");
       writer.writeCharacters("Jack中国");//设置字符
       writer.writeEndElement();//结束name
       writer.writeStartElement("age");
       writer.writeCharacters("90");
       writer.writeEndElement();//分别结束age
       writer.writeEndElement();//结束user
       writer.writeEndElement();//结束users
       writer.close();
    }
}

生成的XML文档如下:

<?xmlversion="1.0"encoding="UTF-8"?>
<users>
    <userid="U00A1">
       <name>Jack中国</name>
       <age>90</age>
    </user>
</users>

以下代码生成带有命名空间的xml文档:

XMLStreamWriter writer = output.createXMLStreamWriter( ... );
writer.writeStartDocument();
writer.setPrefix("c","http://c");
writer.setDefaultNamespace("http://c");
writer.writeStartElement("http://c","a");
writer.writeAttribute("b","blah");
writer.writeNamespace("c","http://c");
writer.writeDefaultNamespace("http://c");
writer.setPrefix("d","http://c");
writer.writeEmptyElement("http://c","d");
writer.writeAttribute("http://c","chris","fry");
writer.writeNamespace("d","http://c");
writer.writeCharacters("Jean Arp");
writer.writeEndElement();
writer.flush();
生成的文档如下:
<?xml version=’1.0’ encoding=’utf-8’?>
<a b="blah" xmlns:c="http://c" xmlns="http://c">
<d:d d:chris="fry" xmlns:d="http://c"/>Jean Arp</a>

12、总结:

StAX的工厂类:

       XMLInputFactory

       XMLOutputFactory

       XMLEventFactory

读取XML的类:

       XMLStreamReader

       XMLEventReader

写XML的类:

       XMLStreamWriter

       XMLEeventWriter

ItratorAPI  (注意与交集)

       XMLEventReader

       XMLEventWriter

CursorAPI

       XMLStreamReader

       XMLStreamWriter

yxkong

这个人很懒,什么都没留下

文章评论