Android-----解析xml文件的三种方式

SAX解析方法介绍:

  SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备。SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。

 

Pull解析器:

  Pull解析是一个while循环,随时可以跳出。Pull解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,因此可以在满足了需要的条件后不再获取事件,结束解析工作。

 

DOM解析:

  DOM解析XML文件时,会将XML的所有内容读取到内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。因为DOM需要将所有内容读取到内存中,所以内存的消耗比较大,不建议使用DOM解析XML文件,若文件较小可行。

 

首先新建一个xml文件,放在res/raw目录下,没有raw目录则新建一个。

要解析的itcase.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<persons>
    <person id="23">
        <name>liming</name>
        <age>30</age>
    </person>
    <person id="20">
        <name>lixiang</name>
        <age>25</age>
    </person>
</persons>

新建一个类存放解析的内容

Person.java如下:

 1 public class Person {
 2     private int id;
 3     private String name;
 4     private int age;
 5 
 6     public int getId() {
 7         return id;
 8     }
 9 
10     public void setId(int id) {
11         this.id = id;
12     }
13 
14     public String getName() {
15         return name;
16     }
17 
18     public void setName(String name) {
19         this.name = name;
20     }
21 
22     public int getAge() {
23         return age;
24     }
25 
26     public void setAge(int age) {
27         this.age = age;
28     }
29 }

以上所需要的准备好了,就开始解析xml工作:

首先是SAX解析

新建一个 XMLContentHandler.java文件内容如下:

 1 public class XMLContentHandler extends DefaultHandler{
 2 
 3     private List<Person> persons = null;
 4     private Person currentPerson;
 5     private String tagName = null;//当前解析的元素标签
 6 
 7     public List<Person> getPersons() {
 8         return persons;
 9     }
10 
11     @Override/**【文档开始时,调用此方法】**/
12     public void startDocument() throws SAXException {
13         persons = new ArrayList<>();
14     }
15 
16     @Override/**【标签开始时,调用此方法】**/
17     /**【uri是命名空间|localName是不带命名空间前缀的标签名|qName是带命名空间前缀的标签名|attributes可以得到所有的属性名和对应的值】**/
18     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
19         if (localName.equals("person")) {
20             currentPerson = new Person();
21             currentPerson.setId(Integer.parseInt(attributes.getValue("id")));
22         }
23         this.tagName = localName;
24     }
25 
26     @Override/**【接收标签中字符数据时,调用此方法】**/
27     /**【ch存放标签中的内容,start是起始位置,length是内容长度】**/
28     public void characters(char[] ch, int start, int length) throws SAXException {
29         if (tagName != null) {
30             String data = new String(ch, start, length);
31             if (tagName.equals("name")) {
32                 this.currentPerson.setName(data);
33             } else if (tagName.equals("age")) {
34                 this.currentPerson.setAge(Short.parseShort(data));
35             }
36         }
37     }
38 
39     @Override/**【标签结束时,调用此方法】**/
40     /**【localName表示元素本地名称(不带前缀),qName表示元素的限定名(带前缀)】**/
41     public void endElement(String uri, String localName, String qName) throws SAXException {
42         if (localName.equals("person")) {
43             persons.add(currentPerson);
44             currentPerson = null;
45         }
46         this.tagName = null;
47     }
48 
49 
50 }

 

新建一个调用XMLContentHandler中方法的XMLParsingMethods.java类,内容如下:

 

 1 public class XMLParsingMethods {
 2 
 3     /**【SAX解析XML文件】**/
 4     public static List<Person> readXmlBySAX(InputStream inputStream) {
 5         try {
 6             /**【创建解析器】**/
 7             SAXParserFactory spf = SAXParserFactory.newInstance();
 8             SAXParser saxParser = spf.newSAXParser();
 9             XMLContentHandler handler = new XMLContentHandler();
10             saxParser.parse(inputStream, handler);
11             inputStream.close();
12             return handler.getPersons();
13         } catch (Exception e) {
14             e.printStackTrace();
15         }
16         return null;
17     }
18 }

 

到这里,SAX解析XML文件工作已经完成了,调用XMLPersingMethods中的readXmlBySAX就可以解析itcase.xml文件。在这里就先不调用,把三种的解析方法讲完再一并调用。

 

DOM解析XML文件:直接在XMLPersingMethods中添加解析方法

 

 1 public class XMLParsingMethods {
 2 
 3     /**【SAX解析XML文件】**/
 4     public static List<Person> readXmlBySAX(InputStream inputStream) {
 5         ......
 6     }
 7 
 8     /**【DOM解析XML文件】**/
 9     public static List<Person> readXmlByDOM(InputStream inputStream){
10         List<Person> persons = new ArrayList<>();
11         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
12         try {
13             DocumentBuilder builder = factory.newDocumentBuilder();
14             Document dom = builder.parse(inputStream);
15 
16             Element root = dom.getDocumentElement();
17             /**【查找所有person节点】**/
18             NodeList items = root.getElementsByTagName("person");
19             for (int i = 0; i < items.getLength(); i++) {
20                 Person person = new Person();
21 
22                 /**【得到第一个person的节点】**/
23                 Element personNode = (Element) items.item(i);
24 
25                 /**【获取person节点的id属性】**/
26                 person.setId(new Integer(personNode.getAttribute("id")));
27 
28                 /**【获取person节点下的所有子节点(标签之间的空白节点和name/age节点)】**/
29                 NodeList childsNodes = personNode.getChildNodes();
30 
31                 /**【遍历所有子节点】**/
32                 for (int j = 0; j < childsNodes.getLength(); j++) {
33                     Node node = (Node) childsNodes.item(j);
34 
35                     /**【判断是否为元素类型】**/
36                     if(node.getNodeType() == Node.ELEMENT_NODE){
37                         Element childNode = (Element) node;
38                         /**【判断是否是name元素】**/
39                         if ("name".equals(childNode.getNodeName())) {
40                             /**【获取name元素下的text节点,然后从text节点获取数据】**/
41                             person.setName(childNode.getFirstChild().getNodeValue());
42                             /**【判断是否是age元素】**/
43                         }else if("age".equals(childNode.getNodeName())){
44                             /**【获取age元素下的text节点,然后从text节点获取数据】**/
45                             person.setAge(new Short(childNode.getFirstChild().getNodeValue()));
46                         }
47                     }
48                 }
49                 persons.add(person);
50             }
51             inputStream.close();
52         } catch (Exception e) {
53             e.printStackTrace();
54         }
55         return persons;
56     }
57 }

 

至此,DOM解析XML文件工作也已经完成了。

 

Pull解析器解析XML文件:

 

 1 public class XMLParsingMethods {
 2 
 3     /**【SAX解析XML文件】**/
 4     public static List<Person> readXmlBySAX(InputStream inputStream) {
 5         ......
 6     }
 7 
 8     /**【DOM解析XML文件】**/
 9     public static List<Person> readXmlByDOM(InputStream inputStream){
10        ......
11     }
12 
13     /**【Pull解析器解析XML文件】**/
14     public static List<Person> readXmlByPull(InputStream inputStream){
15         XmlPullParser parser = Xml.newPullParser();
16         try {
17             parser.setInput(inputStream,"UTF-8");
18             int eventType = parser.getEventType();
19 
20             Person currenPerson = null;
21             List<Person> persons = null;
22 
23             while(eventType != XmlPullParser.END_DOCUMENT){
24                 switch (eventType){
25                     case XmlPullParser.START_DOCUMENT:/**【文档开始事件】**/
26                         persons = new ArrayList<>();
27                         break;
28                     case XmlPullParser.START_TAG:/**【元素(即标签)开始事件】**/
29                         String name = parser.getName();
30                         if(name.equals("person")){
31                             currenPerson = new Person();
32                             currenPerson.setId(new Integer(parser.getAttributeValue(null,"id")));
33                         }else if(currenPerson !=null){
34                             if(name.equals("name")){/**【判断标签名(元素名)是否为name】**/
35                                 currenPerson.setName(parser.nextText());/**【如果后面是text元素,即返回它的值】**/
36                             }else if(name.equals("age")){
37                                 currenPerson.setAge(new Integer(parser.nextText()));
38                             }
39                         }
40                         break;
41                     case XmlPullParser.END_TAG:/**【元素结束事件】**/
42                         if(parser.getName().equalsIgnoreCase("person") && currenPerson != null){
43                             persons.add(currenPerson);
44                             currenPerson = null;
45                         }
46                         break;
47                 }
48                 eventType = parser.next();
49             }
50             inputStream.close();
51             return persons;
52         } catch (Exception e) {
53             e.printStackTrace();
54         }
55         return null;
56     }
57 }

 

至此,SAX、DOM、Pull三种解析XML文件准备好了,接下来分别调用方法:

 

布局文件:

 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     android:orientation="vertical"
 8     tools:context="com.hs.example.exampleapplication.PersonXML">
 9 
10         <TextView
11             android:id="@+id/data"
12             android:layout_width="match_parent"
13             android:layout_height="wrap_content"
14             android:textSize="20sp"
15             android:text="Xml数据:"/>
16 
17     <Button
18         android:id="@+id/btn_read"
19         android:layout_width="match_parent"
20         android:layout_height="wrap_content"
21         android:textSize="25sp"
22         android:text="解析XML文件"/>
23 
24 </LinearLayout>

 

方法调用:

 

 1 public class PersonXML extends AppCompatActivity implements View.OnClickListener{
 2 
 3     Button btn_read;
 4     TextView data ;
 5     List<Person> personList = null;
 6     InputStream inputStream;
 7 
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_personxml);
12 
13         btn_read = this.findViewById(R.id.btn_read);
14         btn_read.setOnClickListener(this);
15 
16         data = this.findViewById(R.id.data);
17 
18         personList = new ArrayList<>();
19     }
20 
21     @Override
22     public void onClick(View view) {
23         switch (view.getId()){
24             case R.id.btn_read:
25                 String result = "";
26                 inputStream = getResources().openRawResource(R.raw.itcase);
27                 if(inputStream == null){
28                     Toast.makeText(this,"InputStream is null",Toast.LENGTH_SHORT).show();
29                 }else{
30                     personList = XMLParsingMethods.readXmlByPull(inputStream); //调用Pull
31                     //personList = XMLParsingMethods.readXmlBySAX(inputStream);//调用SAX
32                     //personList = XMLParsingMethods.readXmlByDOM(inputStream);//调用DOM
33                     if(personList!=null){
34                         for(int i = 0 ;i <personList.size();i++){
35                             String message = "id = " + personList.get(i).getId() + " , name = " + personList.get(i).getName()
36                                     + " , age = " + personList.get(i).getAge() + ".\n";
37                             result += message;
38                         }
39                     }else{
40                         Toast.makeText(this,"persons is null",Toast.LENGTH_SHORT).show();
41                     }
42                     data.setText(result);
43                     XMLParsingMethods.createXmlFile(personList);//这里是接下来使用Pull解析器生成XML文件的方法调用
44                 }
45                 break;
46         }
47 
48     }
49 }

 

运行效果:

 

 

顺道讲下使用Pull解析器生成XML文件:

 

 1 public class XMLParsingMethods {
 2 
 3     /**【SAX解析XML文件】**/
 4     public static List<Person> readXmlBySAX(InputStream inputStream) {
 5         ......
 6     }
 7 
 8     /**【DOM解析XML文件】**/
 9     public static List<Person> readXmlByDOM(InputStream inputStream){
10         ......
11     }
12 
13     /**【Pull解析器解析XML文件】**/
14     public static List<Person> readXmlByPull(InputStream inputStream){
15         ......
16     }
17 
18     /**【使用Pull解析器生成XML文件内容】**/
19     public static String WriteXML(List<Person> persons,Writer writer ){
20         XmlSerializer serializer = Xml.newSerializer();
21         try {
22             serializer.setOutput(writer);
23             serializer.startDocument("UTF-8",true);
24 
25             /**【第一个参数为命名空间,不使用命名空间可以设置为null】**/
26             serializer.startTag("","persons");
27             /**【XML文件中要生成的内容】**/
28             for(Person person : persons){
29                 serializer.startTag("","person");
30                 serializer.attribute("", "id", String.valueOf(person.getId()) );
31 
32                 serializer.startTag("","name");
33                 serializer.text(person.getName());
34                 serializer.endTag("","name");
35 
36                 serializer.startTag("","age");
37                 serializer.text(String.valueOf(person.getAge()));
38                 serializer.endTag("","age");
39 
40                 serializer.endTag("","person");
41             }
42             serializer.endTag("","persons");
43             serializer.endDocument();
44             return writer.toString();
45         } catch (Exception e) {
46             e.printStackTrace();
47         }
48         return null;
49     }
50 
51     /**【生成XML文件代码】**/
52     public static void createXmlFile(List<Person> persons){
53         if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
54             try {
55                 File sdCard = Environment.getExternalStorageDirectory();
56                 File xmlFile = new File(sdCard + File.separator + "testFolder/" + "myitcast.xml");
57                 FileOutputStream outStream =  new FileOutputStream(xmlFile);
58                 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outStream , "UTF-8");
59                 BufferedWriter writerFile = new BufferedWriter(outputStreamWriter);
60 
61                 WriteXML(persons,writerFile);
62                 writerFile.flush();
63                 writerFile.close();
64             } catch (Exception e) {
65                 e.printStackTrace();
66             }
67         }
68     }
69 }

 

运行后:

 

 

 

新建文件要先获得文件操作系统权限,推荐文章:https://blog.csdn.net/weixin_44001878/article/details/89520246

 

以上内容参考于:https://www.open-open.com/lib/view/open1392780226397.html

 

posted @ 2019-05-15 16:58  _小小白  阅读(21674)  评论(0编辑  收藏  举报