Android之SAX生成XML及TransformerHandler解析
来源:互联网 发布:经纬度转换成坐标软件 编辑:程序博客网 时间:2024/06/07 04:31
Android之SAX生成XML
文章链接:http://blog.csdn.net/qq_16628781/article/details/70174654
知识点:
- SAXTransformerFactory类及其对象说明;
- TransformerHandler类及其对象说明;
- Transformer类及其对象说明;
- SAX生成XML实例讲解;
- 新名词记录{SAXTransformerFactory:sax转换工厂类;TransformerHandler:转换事件处理类,触发节点事件;Transformer:设置输出XML文档的属性等;AttributesImpl:设置节点属性的类;}
概述
上一篇讲解了如何利用pull生成XML文件。Android之pull生成XML及XmlSerializer详解
下面我们来讲一下如何利用SAX方式生成XML文件。
SAXTransformerFactory类及其对象
SAXTransformerFactory类继承自TransformerFactory,利用此类,可以创建Transformer类和Templates类的对象(在javax.xml.transform包下面)。
关于SAXTransformerFactory类对象的获取,使用的是下面代码:
SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
去到静态方法newInstance()可以看到如下:
public static TransformerFactory newInstance() throws TransformerFactoryConfigurationError { String className = "org.apache.xalan.processor.TransformerFactoryImpl"; try { return (TransformerFactory) Class.forName(className).newInstance(); } catch (Exception e) { throw new NoClassDefFoundError(className); } }
因为SAXTransformerFactory的构造方法是受保护的,所以不能够直接new出一个对象。这里是利用反射获取到SAXTransformerFactory类实例,主要是获取到TransformerFactoryImpl类对象。关于TransformerFactoryImpl类,它是由Apache提供的类,放在org.apache.xalan.processor目录下面。关于找不到该类的异常就不管了,系统都找不到,我们还能怎么相信Google。
TransformerHandler类及其对象
获取到SAXTransformerFactory工厂类对象之后,就可以获取转换处理类TransformerHandler的对象了。代码如下:
TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler();
那么TransformerHandler类是用来干嘛的呢?TransformerHandler类是用来监听ContentHandler转换事件和转换数据到Result类里面去(对应的设置是setResult(result)方法)。
在利用SAX进行解析XML的时候,我们自定义了一个类,然后继承DefaultHandler处理类,在自定义的类里面,需要重写startElement()、characters()和endElement()等方法。DefaultHandler在继承关系上面,我们也可以看到它是继承了EntityResolver, DTDHandler, ContentHandler, ErrorHandler。看到其中有ContentHandler类。
那么ContentHandler类的作用是什么呢?简单来说,SAX解析基于事件驱动,那么此类的作用就是用户传递和处理事件。我们知道XML文档中的Element是必须要成对出现的,那么这就有两个事件需要触发,开始节点和结束节点。如果解析的时候,parse(InputStream is, DefaultHandler dh)方法参数2需要传入DefaultHandler对象,所以在解析的时候,节点处理类dh会解析到那个节点,就出发哪一个方法。具体请查看
但是这里我们需要的是手动触发事件。所以就需要获取TransformerHandler类对象,此对象可以手动触发事件。在解析使用到的DefaultHandler类和TransformerHandler类具有同样的父类,所以都是可以触发事件的。
获取转换类Transformer
Transformer类其实是用来处理XML文档,并且将它写入到特定的容器中,有以下功能:
设置文档编码方式OutputKeys.ENCODING,
OutputKeys.VERSION版本
是否写出XML文档的说明OutputKeys.OMIT_XML _DECLARATION(取值:yes|no)
文档是否独立STANDALONE(取值:yes|no):no 表示这个 XML 文档不是独立的而是依赖于外部所定义的一个 DTD,yes 表示这个 XML 文档是自包含的(self-contained)。INDENT设置缩进,yes|no。
设置输出
上面说到了,我们如何转换,但是转换的结果应该要怎么处理呢?TransformerHandler类给我们提供了StreamResult()方法,设置输出流。
代码如下:
public void setResult(Result result)
StreamResult实现了Result接口。Result类的作用是建立一个转换结果树。我们要使用的就是其子类。
其构造方法有5个:
public StreamResult()public StreamResult(OutputStream outputStream) public StreamResult(Writer writer)public StreamResult(String systemId)public StreamResult(File f)
传入的参数是结果的接收对象。
无参构造方法,可以调用set方法设置输出接收对象。OutputStream是输出流,比如用文件打开一个输出流,将转换后的数据写入到文件在,因为输出流不能够在程序中得到输出的内容,所以可以使用Writer,创建一个Result,然后在,利用getBuffer()方法或者totring()方法得到结果,再返回出去。或者是一个File文件参数,先写入本地,然后需要的时候再拿出来。
开始创建XML内容了
前面所做的都是准备工作,准备文件的说明和输出等,下面就是开始真正的进行建立文档内容了。一个节点有开始,那么必须有结束,相同节点是成对出现的。如果不是成对出现,那么就会报不匹配的错误。
startDocument()/endDocument()
开始和结束文档节点要触发的方法。所有节点都需要在这两个方法之间完成。
transformerHandler.startDocument();transformerHandler.endDocument();
startElement()/endElement()
public void startElement (String uri, String localName, String qName, Attributes atts)public void endElement (String uri, String localName, String qName)
参数解释:
参数1:命名空间的URI。
参数2:节点名称。
参数3:节点的全限定名。
参数Attributes:此节点的属性。例如< user>节点有id属性,那么就需要设置。
设置属性的方法利用的是Attributes接口的实现类AttributesImpl。AttributesImpl类提供了一系列的方法,比如:
//得到属性的数量public int getLength ()//获取命名空间public String getURI (int index)//得到本地属性名public String getLocalName (int index)//获取属性全限定名public String getQName (int index)//获取属性类型public String getType (int index)//获取第几个属性的值public String getValue (int index)//根据命名空间和本地属性名获取位置public int getIndex (String uri, String localName)//清除该节点所有属性public void clear ()//根据下标移除属性public void removeAttribute (int index)//设置节点的URIpublic void setURI (int index, String uri)//设置属性名public void setLocalName (int index, String localName)//设置属性全限定名public void setQName (int index, String qName)//设置属性类型public void setType (int index, String type)//设置属性的值public void setValue (int index, String value)其中比较要关注的是://新加一个属性addAttribute (String uri, String localName, String qName, String type, String value)//设置属性public void setAttribute (int index, String uri, String localName, String qName, String type, String value)
举例说明:
比如我要在节点user里面加入一个id的属性,最终是这样的效果< user id=”1”>
代码实例:
AttributesImpl attributes = new AttributesImpl();//需要先清除属性,以免上一个节点属性影响本节点属性attributes.clear(); attributes.addAttribute("", "id", "id", "int", //最后一个参数设置属性对象 String.valueOf(userBean.getId())); transformerHandler.startElement("", "user", "user", attributes);
characters()
上面讲完了如何创建节点和给节点加入属性。如果有一个节点下面不再包含子节点,而是一个节点值了。那么该如何来设置值呢?
调用的是public void characters (char ch[], int start, int length);方法
参数1:char字符数组;参数2:数组开始的下边;参数3:开始的长度;
这个方法比较简单哈,只要拿到对应实体的属性值,然后直接设置进去就OK了。
最后我们来看一下中的代码:
对应的实体类UserBean.java
public class UserBean implements Serializable { //串行化版本统一标识符 private static final long serialVersionUID = 1L; private int id; private String userName; private String password; private int age; //省略setter和getter方法}
buildXmlBySax()方法:
/** * SAX生成XML * * @param userBeanList 实体类集合 * @param outputStream 输出流 */ public static void buildXmlBySax(List<UserBean> userBeanList, OutputStream outputStream) { try { SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler(); Transformer transformer = transformerHandler.getTransformer(); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); Result result = new StreamResult(outputStream); transformerHandler.setResult(result); transformerHandler.startDocument(); AttributesImpl attributes = new AttributesImpl(); transformerHandler.startElement("", "users", "users", attributes); for (UserBean userBean : userBeanList) { attributes.clear(); attributes.addAttribute("", "id", "id", "", String.valueOf(userBean.getId())); transformerHandler.startElement("", "user", "user", attributes); attributes.clear(); transformerHandler.startElement("", "userName", "userName", attributes); transformerHandler.characters(userBean.getUserName().toCharArray(), 0, userBean.getUserName().length()); transformerHandler.endElement("", "userName", "userName"); transformerHandler.startElement("", "password", "password", attributes); transformerHandler.characters(userBean.getPassword().toCharArray(), 0, userBean.getPassword().length()); transformerHandler.endElement("", "password", "password"); transformerHandler.startElement("", "age", "age", attributes); transformerHandler.characters(String.valueOf(userBean.getAge()).toCharArray(), 0, String.valueOf(userBean.getAge()).length()); transformerHandler.endElement("", "age", "age"); transformerHandler.endElement("", "user", "user"); } transformerHandler.endElement("", "users", "users"); transformerHandler.endDocument(); } catch (TransformerConfigurationException | SAXException e) { e.printStackTrace(); } }
最后在activity里面调用此方法,这里我获取了设备内部公共存储空间的,并且建立一个文件buildusersbysax.xml,文件名最好小写,别问我为什么,因为可以跨平台。
代码如下:
//文件夹File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);//读取本地XML文件InputStream inputStream = getResources().openRawResource(R.raw.users);//解析本地XML文件List<UserBean> userBeanList = XmlUtil.parseXmlByPull(inputStream);//最后在根据实体集合,生成XML文件try { String outPutPath = file.getAbsolutePath() + "buildusersbysax.xml"; File outFile = new File(outPutPath); if (outFile.exists()){ outFile.delete(); outFile.createNewFile(); }else { outFile.createNewFile(); } CommonLog.logInfo("path:" + outFile.getAbsolutePath()); FileOutputStream fileOutputStream = new FileOutputStream(outFile); XmlUtil.buildXmlBySax(userBeanList, fileOutputStream); } catch (IOException e) { e.printStackTrace(); }
下面是运行生成的XML文件。截图
总结
主要讲解了如何获取SAXTransformerFactory工厂类,建立TransformerHandler转换的处理类,然后在获取Transformer转换类,以及每个类的作用和联系。最后详细说明了下如何触发生成文档需要的每个节点,包括开始建立文档(包括建立XML文件的说明),开始建立节点并且设置节点属性和设置节点值。最后千万别忘了,每个节点都是要成对出现,并且都需要关闭。
关于如何确保关闭节点,我们可以start一个节点,立马就写一个关闭的方法,然后在两个中间写我们需要的代码。
总的来说,sax加你文档并不难。如果有更加复杂的结构,只要理清了结构,那就都不是问题了。
以上就是所有内容,如有任何问题,请及时与我联系,谢谢!
- Android之SAX生成XML及TransformerHandler解析
- Android之SAX解析XML
- Android 解析XML 之SAX
- Android之SAX解析XML
- Android之SAX解析XML
- android xml解析之SAX
- Android之SAX解析XML
- Android xml解析之Sax
- Android之SAX解析XML
- Android SAX解析与生成XML
- Android-Sax解析与生成xml数据
- android之sax解析xml文件
- android开发之sax解析xml文档
- Android之SAX解析XML文件
- android之sax解析xml文件
- android之sax解析xml文件 .
- Android 解析XML之二 SAX
- android之sax解析xml文件
- PAT1026 程序运行时间
- mvc实现图片验证码功能
- mongo(六)Mongo Query
- 房产商,通过媒体辱骂 中国住户是 钉子户,为了获得土地权,所以媒体违法在先,激怒住户,而住户人员而违法了。
- 享元模式
- Android之SAX生成XML及TransformerHandler解析
- NYOJ 1221 找数达人
- Java调用Schema校验xml文件
- Golang操作数据库
- 03-maven安装与配置
- 使用AndroidStudio创建自定义gradle插件并被引用实战例子
- hibernate映射类中通过@Transient可能标注一个属性不是数据库的字段
- XML字符串格式化输出
- cxGrid使用点滴