解析

在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 最终image文件的来源
  2. Android 文件操作,删除,拷贝文件等
  3. Android系统源码编译全过程——下载Android源文件并编译
  4. [Android] 文件夹下文件的个数限制
  5. Android之Telephony各文件解释
  6. Android 自定义View及其在布局文件中的使用示例(二)
  7. android UI设计之 背景透明色 项目资源文件关系

随机推荐

  1. ubuntu怎么安装配置go语言环境
  2. 两个Golang超大文件读取的方案
  3. go语言如何删除链表节点
  4. 详解Golang编译成DLL文件
  5. go语言如何升级版本
  6. go语言如何删除切片
  7. go语言环境如何配置
  8. 学go语言能干什么
  9. go语言开发工具有哪些
  10. go语言环境变量如何设置