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
文章评论