解析

在Android中提供了三种解析XML的方式:SAX(Simple API XML),DOM(Document Objrect Model),以及Android推荐的Pull解析方式.下面就对三种解析方式一一详细阐述。

假设要要解析person.xml文档

<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="1">
<name>zhangsan</name>
<age>21</age>
</person>
<person id="2">
<name>lisi</name>
<age>22</age>
</person>
<person id="3">
<name>wangwu</name>
<age>222</age>
</person>
</persons>

首先介绍SAX解析,SAX是事件驱动型XML解析的一个标准接口不会改变 SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。下面结合代码分析

public class SAXPersonService {

public List<Person> getPersons (InputStream instream) throws Exception{
SAXParserFactory factory = SAXParserFactory.newInstance();//创建SAX解析工厂
SAXParser paser = factory.newSAXParser();//创建SAX解析器
PersonPaser personPaser=new PersonPaser();//创建事件处理程序
paser.parse(instream,personPaser);//开始解析
instream.close();//关闭输入流
return personPaser.getPersons();//返回解析后的内容

}
public final class PersonPaser extends DefaultHandler{//创建事件处理程序,
也就是编写ContentHandler的实现类,一般继承自DefaultHandler类

public List<Person> getPersons() {
return persons;
}
private List<Person> persons=null;
private String tagName=null;
private Person person=null;

{

//遇到文档开始标记的时候创建person集合
public void startDocument() throws SAXExceptionpersons=new ArrayList<Person>();
}
//遇到元素节点开始时候的处理方法
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
tagName = localName;

//如果遇到<person>标记,则创建一个person
if("person".equals(tagName)){
person = new Person();
person.setId(new Integer(attributes.getValue(0)));//取出标记内的属性
}

}

//遇到文本节点时的操作

public void characters(char[] ch, int start, int length)
throws SAXException {
if(tagName!=null){//文本节点必须前面要有元素节点开始标记
String data = new String(ch,start,length);//取出文本节点的值
if("name".equals(tagName)){//如果前面的元素节点开始标记是name
person.setName(data);//则将文本节点的值赋值给person的Name
}else if("age".equals(tagName)){//如果前面元素节点开始标记是age
person.setAge(new Short(data));//则将本节点的值赋值给person的Age
}
}

}

//遇到元素节点结束时候的操作
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("person".equals(localName)){//如果遇到</person>标记
persons.add(person);//则将创建完成的person加入到集合中去
person=null;//置空下一个person
}
tagName=null;//置空已有标记,因为要解析下一个节点了
}
}

至此,SAX解析完毕!

下面介绍DOM解析,DOM,即对象文档模型,它是将整个XML文档载入内存(所以效率较低,不推荐使用),每一个节点当做一个对象,结合代码分析

public class DomPersonService {

public List<Person> getPersons (InputStream instream) throws Exception{
List<Person> persons = new ArrayList<Person>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//创建DOM解析工厂
DocumentBuilder dombuild = factory.newDocumentBuilder();//创建DON解析器
Document dom = dombuild.parse(instream);//开始解析XML文档并且得到整个文档的对象模型
Element root= dom.getDocumentElement();//得到根节点<persons>
NodeList personList = root.getElementsByTagName_r("person");//得到根节点下所有标签为<person>的子节点
for(int i = 0;i<personList.getLength();i++){//遍历person节点
Person person = new Person();//首先创建一个Person
Element personElement = (Element) personList.item(i);//得到本次Person元素节点
person.setId(new Integer(personElement.getAttribute("id")));//得到Person节点中的ID

NodeList personChilds = personElement.getChildNodes();//得到Person节点下的所有子节点
for(int j=0;j<personChilds.getLength();j++){//遍历person节点下的所有子节点
if(personChilds.item(j).getNodeType()==Node.ELEMENT_NODE){//如果是元素节点的话
Element childElement= (Element) personChilds.item(j); //得到该元素节点
if("name".equals(childElement.getNodeName())){//如果该元素节点是name节点
person.setName(childElement.getFirstChild().getNodeValue());//得到name节点下的第一个文本子节点的值
}else if("age".equals(childElement.getNodeName())){//如果该元素节点是age节点、

person.setAge(new Short(childElement.getFirstChild().getNodeValue()));//得到age节点下的第一个文本字节点的值

}
}
}
persons.add(person);//遍历完person下的所有子节点后将person元素加入到集合中去
}
return persons;
}

至此,DOM解析方式结束!

下面介绍Pull解析

public class PulPersonService {

public List<Person> getPersons(InputStream instream) throws Exception {
List<Person> persons =null;
Person person = null;
XmlPullParser parser = Xml.newPullParser();//得到Pull解析器
parser.setInput(instream, "UTF-8");//设置下输入流的编码
int eventType = parser.getEventType();//得到第一个事件类型
while (eventType != XmlPullParser.END_DOCUMENT) {//如果事件类型不是文档结束的话则不断处理事件
switch (eventType) {
case (XmlPullParser.START_DOCUMENT)://如果是文档开始事件
persons = new ArrayList<Person>();创建一个person集合
break;
case (XmlPullParser.START_TAG)://如果遇到标签开始

String tagName = parser.getName();// 获得解析器当前元素的名称
if ("person".equals(tagName)) {//如果当前标签名称是<person>
person = new Person();//创建一个person
person.setId(new Integer(parser.getAttributeValue(0)));//将元素的属性值赋值给id
}
if (person != null) {//如果person已经创建完成
if ("name".equals(tagName))//如果当前节点标记是name
person.setName(new String(parser.nextText()));
else if ("age".equals(tagName))//如果当前元素节点标记是age
person.setAge(new Short(parser.nextText()));
}
break;
case (XmlPullParser.END_TAG)://如果遇到标签结束

if ("person".equals(parser.getName())) {//如果是person标签结束
persons.add(person);//将创建完成的person加入集合
person = null;//并且置空
}
break;
}
eventType=parser.next();//进入下一个事件处理
}
return persons;
}

修改

1:用DOM解析形成节点列表,节点内容与内存地址映射,改节点内容就是修改内存中的Document对象
然后使用Document对象(在内存中已经经过修改):
document是Documentdocument;

TransformerFactorytransformerFactory=TransformerFactory.newInstance();
Transformertransformer=transformerFactory.newTransformer();
SourcexmlSource=newDOMSource(document);
ResultoutputTarget=newStreamResult(newFile("F:\\javaweb20120208_workspace\\day3\\orders.xml"));//xm文件所在位置 transformer.transform(xmlSource,outputTarget);//提交覆盖原来的xml

2:用SAX或PULL解析生成实体列表,LIST<类>实体列表名
然后修改列表中的对应的实体。
使用修改后的实体列表用XmlSerializer序列化写回原地址的XML文件覆盖

例子如下:

*@return生成的xml文件的字符串表示
*/
privateStringproduceXml(){

StringWriterstringWriter=newStringWriter();
ArrayList<Beauty>beautyList=getData();
try{
//获取XmlSerializer对象
XmlPullParserFactoryfactory=XmlPullParserFactory.newInstance();
XmlSerializerxmlSerializer=factory.newSerializer();
//设置输出流对象
xmlSerializer.setOutput(stringWriter);

xmlSerializer.startDocument("utf-8",true);
xmlSerializer.startTag(null,"beauties");
for(Beautybeauty:beautyList){

xmlSerializer.startTag(null,"beauty");

xmlSerializer.startTag(null,"name");
xmlSerializer.text(beauty.getName());
xmlSerializer.endTag(null,"name");

xmlSerializer.startTag(null,"age");
xmlSerializer.text(beauty.getAge());
xmlSerializer.endTag(null,"age");

xmlSerializer.endTag(null,"beauty");
}
xmlSerializer.endTag(null,"beauties");
xmlSerializer.endDocument();
}catch(Exceptione){
e.printStackTrace();
}
returnstringWriter.toString();

}



工具

在项目中,我们很多都用到了xml文件,无论是参数配置还是与其它系统的数据交互。
今天就来讲一下Java 中使用dom4j来操作XML文件。

我们需要引入的包:

//文件包
importjava.io.ByteArrayOutputStream;
importjava.io.File;
importjava.io.FileWriter;
//工具包
importjava.util.Iterator;
importjava.util.List;
//dom4j包
importorg.dom4j.Attribute;
importorg.dom4j.Document;
importorg.dom4j.DocumentHelper;
importorg.dom4j.Element;
importorg.dom4j.io.OutputFormat;
importorg.dom4j.io.SAXReader;
importorg.dom4j.io.XMLWriter;

1、将XML文件的内容转化为String

/**
*doc2String
*将xml文档内容转为String
*@return字符串
*@paramdocument
*/
publicstaticStringdoc2String(Documentdocument)
{
Strings="";
try
{
//使用输出流来进行转化
ByteArrayOutputStreamout=newByteArrayOutputStream();
//使用GB2312编码
OutputFormatformat=newOutputFormat("",true,"GB2312");
XMLWriterwriter=newXMLWriter(out,format);
writer.write(document);
s=out.toString("GB2312");
}catch(Exceptionex)
{
ex.printStackTrace();
}
returns;
}

2、将符合XML格式的String 转化为XML Document

/**
*string2Document
*将字符串转为Document
*@return
*@paramsxml格式的字符串
*/
publicstaticDocumentstring2Document(Strings)
{
Documentdoc=null;
try
{
doc=DocumentHelper.parseText(s);
}catch(Exceptionex)
{
ex.printStackTrace();
}
returndoc;
}

3、将Document对象保存为一个xml文件到本地

/**
*doc2XmlFile
*将Document对象保存为一个xml文件到本地
*@returntrue:保存成功flase:失败
*@paramfilename保存的文件名
*@paramdocument需要保存的document对象
*/
publicstaticbooleandoc2XmlFile(Documentdocument,Stringfilename)
{
booleanflag=true;
try
{
/*将document中的内容写入文件中*/
//默认为UTF-8格式,指定为"GB2312"
OutputFormatformat=OutputFormat.createPrettyPrint();
format.setEncoding("GB2312");
XMLWriterwriter=newXMLWriter(newFileWriter(newFile(filename)),format);
writer.write(document);
writer.close();
}catch(Exceptionex)
{
flag=false;
ex.printStackTrace();
}
returnflag;
}

4、将xml格式的字符串保存为本地文件,如果字符串格式不符合xml规则,则返回失败

/**
*string2XmlFile
*将xml格式的字符串保存为本地文件,如果字符串格式不符合xml规则,则返回失败
*@returntrue:保存成功flase:失败
*@paramfilename保存的文件名
*@paramstr需要保存的字符串
*/
publicstaticbooleanstring2XmlFile(Stringstr,Stringfilename)
{
booleanflag=true;
try
{
Documentdoc=DocumentHelper.parseText(str);
flag=doc2XmlFile(doc,filename);
}catch(Exceptionex)
{
flag=false;
ex.printStackTrace();
}
returnflag;
}

5、载入一个xml文档

/**
*load
*载入一个xml文档
*@return成功返回Document对象,失败返回null
*@paramuri文件路径
*/
publicstaticDocumentload(Stringfilename)
{
Documentdocument=null;
try
{
SAXReadersaxReader=newSAXReader();
document=saxReader.read(newFile(filename));
}
catch(Exceptionex){
ex.printStackTrace();
}
returndocument;
}

6、演示String保存为xml文件

/**
*xmlWriteDemoByString
*演示String保存为xml文件
*/
publicvoidxmlWriteDemoByString()
{
Strings="";
/**xml格式标题"<?xmlversion='1.0'encoding='GB2312'?>"可以不用写*/
s="<config>\r\n"
+"<ftpname='DongDian'>\r\n"
+"<ftp-host>127.0.0.1</ftp-host>\r\n"
+"<ftp-port>21</ftp-port>\r\n"
+"<ftp-user>cxl</ftp-user>\r\n"
+"<ftp-pwd>longshine</ftp-pwd>\r\n"
+"<!--ftp最多尝试连接次数-->\r\n"
+"<ftp-try>50</ftp-try>\r\n"
+"<!--ftp尝试连接延迟时间-->\r\n"
+"<ftp-delay>10</ftp-delay>\r\n"
+"</ftp>\r\n"
+"</config>\r\n";
//将文件生成到classes文件夹所在的目录里
string2XmlFile(s,"xmlWriteDemoByString.xml");
//将文件生成到classes文件夹里
string2XmlFile(s,"classes/xmlWriteDemoByString.xml");
}

7、演示手动创建一个Document,并保存为XML文件

/**
*演示手动创建一个Document,并保存为XML文件
*/
publicvoidxmlWriteDemoByDocument()
{
/**建立document对象*/
Documentdocument=DocumentHelper.createDocument();
/**建立config根节点*/
ElementconfigElement=document.addElement("config");
/**建立ftp节点*/
configElement.addComment("东电ftp配置");
ElementftpElement=configElement.addElement("ftp");
ftpElement.addAttribute("name","DongDian");
/**ftp属性配置*/
ElementhostElement=ftpElement.addElement("ftp-host");
hostElement.setText("127.0.0.1");
(ftpElement.addElement("ftp-port")).setText("21");
(ftpElement.addElement("ftp-user")).setText("cxl");
(ftpElement.addElement("ftp-pwd")).setText("longshine");
ftpElement.addComment("ftp最多尝试连接次数");
(ftpElement.addElement("ftp-try")).setText("50");
ftpElement.addComment("ftp尝试连接延迟时间");
(ftpElement.addElement("ftp-delay")).setText("10");
/**保存Document*/
doc2XmlFile(document,"classes/xmlWriteDemoByDocument.xml");
}

8、演示读取文件的具体某个节点的值

/**
*演示读取文件的具体某个节点的值
*/
publicstaticvoidxmlReadDemo()
{
Documentdoc=load("classes/xmlWriteDemoByDocument.xml");
//Elementroot=doc.getRootElement();
/**先用xpath查找所有ftp节点并输出它的name属性值*/
Listlist=doc.selectNodes("/config/ftp");
Iteratorit=list.iterator();
while(it.hasNext())
{
ElementftpElement=(Element)it.next();
System.out.println("ftp_name="+ftpElement.attribute("name").getValue());
}
/**直接用属性path取得name值*/
list=doc.selectNodes("/config/ftp/@name");
it=list.iterator();
while(it.hasNext())
{
Attributeattribute=(Attribute)it.next();
System.out.println("@name="+attribute.getValue());
}
/**直接取得DongDianftp的ftp-host的值*/
list=doc.selectNodes("/config/ftp/ftp-host");
it=list.iterator();
ElementhostElement=(Element)it.next();
System.out.println("DongDian'sftp_host="+hostElement.getText());
}

9、修改或删除某个值或属性

/**ftp节点删除ftp-host节点*/
ftpElement.remove(hostElement);
/**ftp节点删除name属性*/
ftpElement.remove(nameAttribute);
/**修改ftp-host的值*/
hostElement.setText("192.168.0.1");
/**修改ftp节点name属性的值*/
nameAttribute.setValue("ChiFeng");

更多相关文章

  1. Android(安卓)Service启动(二) bindService()启动过程以及原理解析
  2. android 资源res下目录使用
  3. Android的数据存储方式
  4. Android(安卓)常用代码集合
  5. android NDK学习篇3之two-libs——使用(多个)静态库生成动态库
  6. 通过Titanium Studio为Android(安卓)APK签名
  7. Android(安卓)最终image文件的来源
  8. 手动编译源码,打造自己的增量更新。
  9. NPM 和webpack 的基础使用

随机推荐

  1. Core Java 并发:理解并发概念
  2. 5个有趣的程序员彩蛋
  3. 模块_Haskell笔记2
  4. Python&C++造就Google人工智能系统Tensor
  5. 大厂面试官竟然这么爱问Kafka,一连八个Kaf
  6. 1计算机网络【开山篇】
  7. 一场函数式思维模式的洗礼
  8. API注入机制及插件启动流程_VSCode插件开
  9. 使用Docker Compose部署SpringBoot应用
  10. IPython高级用法及注意事项