java StAX 基于流的XML编程接口
原创    loonbs    发表于:2018-03-30 15:18:16
  阅读 :31   收藏   编辑

之前学习java xml ,参考的笔记,已经忘记原作者,如有侵权,告知,立删。

1、StAX是什么?

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

1、 文档对象模型(DOM-Document Object 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 允许应用程序代码把这些事件逐个拉出来,而不用提供在解析器方便时从解析器中接收事件的处理程序。

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 void flush() 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文档如下:

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="U001">
        <name>Jack</name>
        <age>23</age>
    </user>
    <user id="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文档:

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="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()){
            int element = 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;
import org.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文档如下:

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="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

Itrator API (注意与交集)

    XMLEventReader
    XMLEventWriter

Cursor API

XMLStreamReader
XMLStreamWriter
评论
条评论