首先,我得声明,本博客的思想主要参考了此博客:http://blog.csdn.net/liuhe688/article/details/6415593
不过代码我自己一句句敲的
好了,首先讲一下解析XML的三种方式:(恕我粘贴一下哈)
SAX解析器:
SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。
SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。
DOM解析器:
DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。
由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。
PULL解析器:
PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。
好了,介绍完三种解析方式,现在开始进行xml文件的解析与生成了。
首先需要在项目的assets目录里面放置一个xml文件来给我们此次做xml源文件,当然,实际应用当中,可以通过httpClient 或者URLConnection的方式进行获取服务器的xml文件来与服务器进行交互,这里我就直接放到项目里面了,方便操作一些,以下是我的xml文件,比较简单,实践的时候,可以自己随意想一种格式的xml文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <addresses> 3 <address> 4 <id>01</id> 5 <name>北京</name> 6 <money>10000</money> 7 </address> 8 <address> 9 <id>02</id> 10 <name>上海</name> 11 <money>8999</money> 12 </address> 13 <address> 14 <id>03</id> 15 <name>广州</name> 16 <money>7500</money> 17 </address> 18 <address> 19 <id>04</id> 20 <name>深圳</name> 21 <money>8500</money> 22 </address> 23 </addresses>
首先,针对我这个xml文件新建一个Address类,用来封装数据:
1 package com.oysd.ouyangxml.model; 2 3 public class Address { 4 5 private int id; 6 private String name; 7 private float money; 8 public int getId() { 9 return id; 10 } 11 public void setId(int id) { 12 this.id = id; 13 } 14 public String getName() { 15 return name; 16 } 17 public void setName(String name) { 18 this.name = name; 19 } 20 public float getMoney() { 21 return money; 22 } 23 public void setMoney(float money) { 24 this.money = money; 25 } 26 27 @Override 28 public String toString() { 29 30 return "id: " + id + " " + 31 "name: " + name + " " + 32 "money:" + money; 33 } 34 35 }
然后就是新建一个接口类,为什么要新建一个接口类呢?因为我们这次需要使用三种方式来进行解析xml文件,
而且,每一次解析的时候,都需要调用这一种方式的解析方法,每一次生成xml文件的,也需要调用这种方式的生成方法,
那么,我们直接定义这个接口类,然后,在这个接口类里面声明两个方法,一个是解析xml的方法,另一个是生成xml文件的方法,
然后,让这三种方式都implements这个接口,然后都需要实现这个接口的两个方法,以下是AddressParser接口类:
1 package com.oysd.ouyangxml.parser; 2 3 import java.io.InputStream; 4 import java.util.List; 5 6 import com.oysd.ouyangxml.model.Address; 7 8 public interface AddressParser { 9 10 /** 11 * 解析xml的文件的输入流,返回Address对象集合 12 * @param is 13 * @return 14 * @throws Exception 15 */ 16 public List<Address> parser(InputStream is) throws Exception; 17 18 /** 19 * 序列化Address集合对象,形成xml形式的字符串 20 * @param addresses 21 * @return 22 * @throws Exception 23 */ 24 public String outPutXml(List<Address> addresses) throws Exception; 25 26 }
接口类做好之后,我们就可以按三种方式一一进行解析与生成了
第一:SAX解析与生成XML文件
以下代码是我的SaxAddressParser.java的代码:
1 package com.oysd.ouyangxml.parser; 2 3 import java.io.InputStream; 4 import java.io.StringWriter; 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import javax.xml.parsers.SAXParser; 9 import javax.xml.parsers.SAXParserFactory; 10 import javax.xml.transform.OutputKeys; 11 import javax.xml.transform.Transformer; 12 import javax.xml.transform.TransformerFactory; 13 import javax.xml.transform.sax.SAXTransformerFactory; 14 import javax.xml.transform.sax.TransformerHandler; 15 import javax.xml.transform.stream.StreamResult; 16 17 import org.xml.sax.Attributes; 18 import org.xml.sax.SAXException; 19 import org.xml.sax.helpers.AttributesImpl; 20 import org.xml.sax.helpers.DefaultHandler; 21 22 import android.database.CursorJoiner.Result; 23 24 import com.oysd.ouyangxml.model.Address; 25 26 27 public class SaxAddressParser implements AddressParser{ 28 29 /** 30 * 解析xml文件 31 */ 32 @Override 33 public List<Address> parser(InputStream is) throws Exception { 34 //取得SAXParserFactory实例 35 SAXParserFactory factory = SAXParserFactory.newInstance(); 36 //通过factory实例获取SAXParser实例 37 SAXParser parser = factory.newSAXParser(); 38 //实例化自定义的Handler 39 OuYangHandler oyHandler = new OuYangHandler(); 40 //根据自定义的Handler规则解析输入流 41 parser.parse(is, oyHandler); 42 return oyHandler.getAddresses(); 43 } 44 45 /** 46 * 将xml文件输出到文件 47 */ 48 @Override 49 public String outPutXml(List<Address> addresses) throws Exception { 50 //取得SAXTransformerFactory实例 51 SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance(); 52 //从factory获取TransformerHandler实例 53 TransformerHandler handler = factory.newTransformerHandler(); 54 //从handler获取Transformer实例 55 Transformer transformer = handler.getTransformer(); 56 57 // 设置输出采用的编码方式 58 transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8"); 59 // 是否自动添加额外的空白 60 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 61 // 是否忽略XML声明 62 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); 63 64 StringWriter writer = new StringWriter(); 65 StreamResult result = new StreamResult(writer); 66 handler.setResult(result); 67 68 String uri = ""; //代表命名空间的URI 当URI无值时 须置为空字符串 69 String localName = ""; //命名空间的本地名称(不包含前缀) 当没有进行命名空间处理时 须置为空字符串 70 71 handler.startDocument(); 72 handler.startElement(uri, localName, "addresses", null); 73 AttributesImpl attrs = new AttributesImpl(); //负责存放元素的属性信息 74 75 char ch [] = null; 76 for(Address address:addresses){ 77 attrs.clear(); 78 //添加一个名为id的属性(type影响不大,这里设为string) 79 attrs.addAttribute(uri, localName, "id", "string", String.valueOf(address.getId())); 80 //开始一个address元素 关联上面设定的id属性 81 handler.startElement(uri, localName, "address", attrs); 82 //开始一个name元素 没有属性 83 handler.startElement(uri, localName, "name", null); 84 85 ch = String.valueOf(address.getName()).toCharArray(); 86 handler.characters(ch, 0, ch.length);//设置name元素的文本节点 87 handler.endElement(uri, localName, "name"); 88 //开始一个money元素 没有属性 89 handler.startElement(uri, localName, "money", null); 90 ch = String.valueOf(address.getMoney()).toCharArray(); 91 handler.characters(ch, 0, ch.length);//设置money元素的文本节点 92 handler.endElement(uri, localName, "money"); 93 handler.endElement(uri, localName, "address"); 94 95 96 } 97 handler.endElement(uri, localName, "addresses"); 98 handler.endDocument(); 99 return writer.toString(); 100 } 101 102 103 public class OuYangHandler extends DefaultHandler{ 104 105 private List<Address> addresses; 106 private Address address; 107 private StringBuilder builder; 108 109 110 /** 111 * 返回解析后的Address对象集合 112 * @return 113 */ 114 public List<Address> getAddresses(){ 115 return addresses; 116 } 117 118 /** 119 * characters方法被调用,我们可以获取节点内的文本信息 120 */ 121 @Override 122 public void characters(char[] ch, int start, int length) 123 throws SAXException { 124 super.characters(ch, start, length); 125 //将读取的字符数组追加到builder中 126 builder.append(ch, start, length); 127 } 128 129 @Override 130 public void endDocument() throws SAXException { 131 // TODO Auto-generated method stub 132 super.endDocument(); 133 } 134 135 /** 136 * 执行到最后一个节点,endElement方法被调用,我们可以做收尾的相关操作 137 */ 138 @Override 139 public void endElement(String uri, String localName, String qName) 140 throws SAXException { 141 super.endElement(uri, localName, qName); 142 143 if(localName.equals("id")){ 144 address.setId(Integer.parseInt(builder.toString())); 145 }else if(localName.equals("name")){ 146 address.setName(builder.toString()); 147 148 }else if(localName.equals("money")){ 149 address.setMoney(Float.parseFloat(builder.toString())); 150 }else if(localName.equals("address")){ 151 addresses.add(address); 152 } 153 } 154 155 /** 156 * 文档准备好之后,开始解析文档 157 */ 158 @Override 159 public void startDocument() throws SAXException { 160 super.startDocument(); 161 //初始一下 162 addresses = new ArrayList<Address>(); 163 builder = new StringBuilder(); 164 } 165 166 /** 167 * 当执行文档时遇到起始节点,startElement方法将会被调用 168 */ 169 @Override 170 public void startElement(String uri, String localName, String qName, 171 Attributes attributes) throws SAXException { 172 super.startElement(uri, localName, qName, attributes); 173 if(localName.equals("address")){ 174 address = new Address(); 175 } 176 builder.setLength(0);//将字符长度设置为0 以便重新开始读取元素内的字符节点 177 } 178 179 } 180 181 }
稍微讲一下里面的解析xml的带代码,使用SAX解析xml,需要使用到DefaultHandler来处理解析过程中的一些事件
DefaultHandler是一个事件处理器,可以接收解析器报告的所有事件,处理所发现的数据。它实现了EntityResolver接口、DTDHandler接口、ErrorHandler接口和ContentHandler接口。这几个接口代表不同类型的事件处理器,我定义了一个OuYangHandler扩展至DefaultHandler,
最主要的是重写startElement方法、characters方法和endElement方法,
当执行文档时遇到起始节点,startElement方法将会被调用,我们可以获取起始节点相关信息;
然后characters方法被调用,我们可以获取节点内的文本信息;
最后endElement方法被调用,我们可以做收尾的相关操作。
还有就是里面的生成XML的方法,个人感觉使用SAX的这个方式来生成xml比较麻烦,不过,逻辑性也比较强,
牢记自己xml文件的格式,然后通过TransFormerHandler的实例handler来构造格式:
格式如下:
handler.startDocument();
handler.startElement();
handler.startElement();
handler.endElement();
handler.endElement();
handler.endDocument();
至于中间的数据,通过handler.characters();方法进行赋值,这里需要传什么样的参数,就不仔细说了, 可以直接看源码;
解析完了xml文件返回了一个List<Address>,在MainActivity里面进行输出,布局就不贴了,超简陋,两个Button,一个TextView
1 package com.oysd.ouyangxml; 2 3 import java.io.DataOutputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.util.List; 8 9 import com.oysd.ouyangxml.model.Address; 10 import com.oysd.ouyangxml.parser.AddressParser; 11 import com.oysd.ouyangxml.parser.DomAddressParser; 12 import com.oysd.ouyangxml.parser.PullAddressParser; 13 import com.oysd.ouyangxml.parser.SaxAddressParser; 14 15 import android.app.Activity; 16 import android.content.Context; 17 import android.os.Bundle; 18 import android.util.Log; 19 import android.view.Menu; 20 import android.view.MenuItem; 21 import android.view.View; 22 import android.view.View.OnClickListener; 23 import android.widget.Button; 24 import android.widget.TextView; 25 26 public class MainActivity extends Activity implements OnClickListener { 27 28 private Button btnParser; 29 private Button btnOutPut; 30 private TextView tvXML; 31 32 private static final String TAG = "XML"; 33 private AddressParser parser; 34 private List<Address> addresses; 35 36 @Override 37 protected void onCreate(Bundle savedInstanceState) { 38 super.onCreate(savedInstanceState); 39 setContentView(R.layout.activity_main); 40 initView(); 41 } 42 43 private void initView(){ 44 btnParser = (Button) findViewById(R.id.btnParser); 45 btnOutPut = (Button) findViewById(R.id.btnOutPut); 46 tvXML = (TextView) findViewById(R.id.tvXml); 47 48 btnParser.setOnClickListener(this); 49 btnOutPut.setOnClickListener(this); 50 } 51 52 @Override 53 public void onClick(View v) { 54 // TODO Auto-generated method stub 55 switch(v.getId()){ 56 case R.id.btnParser: 57 try { 58 InputStream is = getAssets().open("address.xml"); 59 parser = new SaxAddressParser();//SAX方式解析XML文件 60 //parser = new DomAddressParser();//DOM方式解析XML文件 61 //parser = new PullAddressParser();//PULL方式解析XML文件 62 addresses = parser.parser(is); 63 for(Address address : addresses){ 64 Log.d(TAG , address.toString()); 65 tvXML.append(address.toString()); 66 tvXML.append(" "); 67 } 68 69 } catch (Exception e) { 70 // TODO Auto-generated catch block 71 //Log.d(TAG, e.toString()); 72 e.printStackTrace(); 73 74 } 75 break; 76 case R.id.btnOutPut: 77 try { 78 Process process = null; 79 DataOutputStream os = null; 80 try { 81 process = Runtime.getRuntime().exec("su"); 82 os = new DataOutputStream(process.getOutputStream()); 83 //os.writeBytes(command+" "); 84 os.writeBytes("exit "); 85 os.flush(); 86 process.waitFor(); 87 } catch (Exception e) { 88 Log.d("*** DEBUG ***", "Unexpected error - Here is what I know: "+e.getMessage()); 89 } 90 finally { 91 try { 92 if (os != null) { 93 os.close(); 94 } 95 process.destroy(); 96 } catch (Exception e) { 97 // nothing 98 } 99 } 100 String xml = parser.outPutXml(addresses); 101 FileOutputStream fos = openFileOutput("address.xml", Context.MODE_PRIVATE); 102 fos.write(xml.getBytes("UTF-8")); 103 104 } catch (Exception e) { 105 // TODO Auto-generated catch block 106 e.printStackTrace(); 107 } 108 109 110 } 111 112 } 113 114 115 }
第二种:DOM方式解析与生成XML文件
以下是我的DomAddressParser.java的代码:
1 package com.oysd.ouyangxml.parser; 2 3 import java.io.InputStream; 4 import java.io.StringWriter; 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import javax.xml.parsers.DocumentBuilder; 9 import javax.xml.parsers.DocumentBuilderFactory; 10 import javax.xml.transform.OutputKeys; 11 import javax.xml.transform.Result; 12 import javax.xml.transform.Source; 13 import javax.xml.transform.Transformer; 14 import javax.xml.transform.TransformerFactory; 15 import javax.xml.transform.dom.DOMSource; 16 import javax.xml.transform.stream.StreamResult; 17 18 import org.w3c.dom.Document; 19 import org.w3c.dom.Element; 20 import org.w3c.dom.Node; 21 import org.w3c.dom.NodeList; 22 23 import com.oysd.ouyangxml.model.Address; 24 25 26 public class DomAddressParser implements AddressParser{ 27 28 @Override 29 public List<Address> parser(InputStream is) throws Exception { 30 List<Address> addresses = new ArrayList<Address>(); 31 //获得DocumentBuilderFactory实例 32 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 33 //通过factory获得DocumentBuilder实例 34 DocumentBuilder builder = factory.newDocumentBuilder(); 35 //解析输入的xml文件,获取Document实例 36 Document doc = builder.parse(is); 37 Element rootElement = doc.getDocumentElement();//获取到根节点 38 NodeList items = rootElement.getElementsByTagName("address"); 39 for (int i = 0; i < items.getLength(); i++) { 40 Address address = new Address(); 41 Node item = items.item(i); 42 NodeList properties = item.getChildNodes(); 43 for (int j = 0; j < properties.getLength(); j++) { 44 Node property = properties.item(j); 45 String nodeName = property.getNodeName(); 46 if(nodeName.equals("id")){ 47 address.setId(Integer.parseInt(property.getFirstChild().getNodeValue())); 48 }else if(nodeName.equals("name")){ 49 address.setName(property.getFirstChild().getNodeValue()); 50 51 }else if(nodeName.equals("money")){ 52 address.setMoney(Float.parseFloat(property.getFirstChild().getNodeValue())); 53 } 54 } 55 addresses.add(address); 56 } 57 return addresses; 58 } 59 60 @Override 61 public String outPutXml(List<Address> addresses) throws Exception { 62 63 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 64 DocumentBuilder builder = factory.newDocumentBuilder(); 65 Document doc = builder.newDocument();//由builder创建新文档 66 Element rootElement = doc.createElement("addresses"); 67 for(Address address:addresses){ 68 Element addressElement = doc.createElement("address"); 69 addressElement.setAttribute("id", address.getId() + ""); 70 71 Element nameElement = doc.createElement("name"); 72 nameElement.setTextContent(address.getName()); 73 addressElement.appendChild(nameElement); 74 75 Element moneyElement = doc.createElement("money"); 76 moneyElement.setTextContent(String.valueOf(address.getMoney())); 77 addressElement.appendChild(moneyElement); 78 79 rootElement.appendChild(addressElement); 80 } 81 doc.appendChild(rootElement); 82 83 TransformerFactory transFactory = TransformerFactory.newInstance(); 84 Transformer transformer = transFactory.newTransformer(); 85 transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");//设置编码 86 transformer.setOutputProperty(OutputKeys.INDENT, "yes");//自动添加额外空白处 87 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");//是否忽略xml声明 88 89 90 StringWriter writer = new StringWriter(); 91 92 Source source = new DOMSource(doc);//声明文档来源是doc 93 Result result = new StreamResult(writer);//表明目标结果为writer 94 transformer.transform(source, result); //开始转换 95 96 return writer.toString(); 97 } 98 99 100 }
解析XML的文件的步骤差不多
生成XML的格式(通过Document实例对象doc来设置好格式):
doc.createElement();
doc.createElement();
doc.createElement();
doc.appendChild();
doc.appendChild();
doc.appendChild();
其中添加具体的数据使用:Element实例对象进行setTextContent来设置值
调用这种方式,在MainActivity里面实例对象的时候,换一个类就好了
第三步:使用PULL解析与生成XML文件
以下是PullAddressParser.java的代码:
1 package com.oysd.ouyangxml.parser; 2 3 import java.io.InputStream; 4 import java.io.StringWriter; 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import org.xmlpull.v1.XmlPullParser; 9 import org.xmlpull.v1.XmlSerializer; 10 11 import android.util.Log; 12 import android.util.Xml; 13 14 import com.oysd.ouyangxml.model.Address; 15 16 public class PullAddressParser implements AddressParser{ 17 18 private static final String TAG = "PullAddressParser"; 19 20 @Override 21 public List<Address> parser(InputStream is) throws Exception { 22 23 List<Address> addresses = null; 24 Address address = null; 25 //由android.util.Xml创建一个XmlPullParser实例 26 XmlPullParser parser = Xml.newPullParser(); 27 //设置输入流 并指明编码方式 28 parser.setInput(is, "utf-8"); 29 int eventType = parser.getEventType(); 30 while(eventType != XmlPullParser.END_DOCUMENT){ 31 String str = parser.getName(); 32 33 switch(eventType){ 34 case XmlPullParser.START_DOCUMENT: 35 addresses = new ArrayList<Address>(); 36 break; 37 case XmlPullParser.START_TAG: 38 if(parser.getName().equals("address")){ 39 address = new Address(); 40 41 }else if(parser.getName().equals("id")){ 42 //Log.d(TAG, parser.getText()); 43 eventType = parser.next(); 44 //Log.d(TAG, parser.getText()); 45 address.setId(Integer.parseInt(parser.getText())); 46 47 }else if(parser.getName().equals("name")){ 48 //Log.d(TAG, parser.getText()); 49 eventType = parser.next(); 50 //Log.d(TAG, parser.getText()); 51 address.setName(parser.getText()); 52 53 }else if(parser.getName().equals("money")){ 54 //Log.d(TAG, parser.getText()); 55 56 eventType = parser.next(); 57 //Log.d(TAG, parser.getText()); 58 address.setMoney(Float.parseFloat(parser.getText())); 59 60 } 61 break; 62 case XmlPullParser.END_TAG: 63 if(parser.getName().equals("address")){ 64 addresses.add(address); 65 address = null; 66 } 67 break; 68 } 69 //Log.d(TAG, parser.getText()); 70 eventType = parser.next(); 71 //Log.d(TAG, parser.getText()); 72 } 73 74 return addresses; 75 } 76 77 @Override 78 public String outPutXml(List<Address> addresses) throws Exception { 79 80 XmlSerializer serializer = Xml.newSerializer();//由android.util.Xml创建一个XmlSerializer实例 81 StringWriter writer = new StringWriter(); 82 serializer.setOutput(writer);//设置输出方向为writer 83 serializer.startDocument("utf-8", true); 84 serializer.startTag("", "addresses"); 85 for(Address address : addresses){ 86 serializer.startTag("", "book"); 87 serializer.attribute("", "id", address.getId() + ""); 88 serializer.startTag("", "name"); 89 serializer.text(address.getName()); 90 serializer.endTag("", "name"); 91 serializer.startTag("", "moeny"); 92 serializer.text(address.getMoney() + ""); 93 serializer.endTag("", "money"); 94 95 serializer.endTag("", "address"); 96 } 97 serializer.endTag("", "addresses"); 98 serializer.endDocument(); 99 return writer.toString(); 100 } 101 102 }
生成XML文件的格式(直接通过XmlSeriaizer实例对象serializer进行生成格式):
serializer.startDocument();
serializer.startTag();
serializer.startTag();
serializer.endTag();
serializer.endTag();
serializer.endDocument();
设置值的时候,使用:serializer.Text();
对于这三种解析器各有优点,其中PULL解析器方便快捷,因为SAX解析器操作起来太笨重,DOM不适合文档较大,内存较小的场景,唯有PULL轻巧灵活,速度快,占用内存小,使用非常顺手。各位按自己的爱好来选择吧