Android学习记录(十五)

1.XML数据解析

1.1 要点介绍

1.1.1 XML格式数据的简单理解

XML数据全名叫做可拓展标记语言,类似于HTML。在很多时候我们将xml用来储存数据,可以将其看作一个微型的数据库,比如我们Android中的SharedPreference就是使用XML文件来保存配置信息的,而我们的SQLite的底层也是一个xml文件;而在网络应用方面通常作为信息的载体,我们通常把数据包装成xml来传递。

1.1.2 三种解析XML方法

1.1.2.1 SAX解析XML

对文档进行顺序扫描,当扫描到文档(document)开始与结束,元素(element)开始与结束,文档(document)结束等地方时,通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。解析速度快,占用内存也较少,每需要解析一类xml就需要编写新的适合该类XML的处理类。

可供重写的方法:
在这里插入图片描述
核心代码:

SAX解析类:SaxHelper.java:

public class SaxHelper extends DefaultHandler {
    
    
    private Person person;
    private ArrayList<Person> persons;
    //当前解析的元素标签
    private String tagName = null;

    /**
     * 当读取到文档开始标志是触发,通常在这里完成一些初始化操作
     */
    @Override
    public void startDocument() throws SAXException {
    
    
        this.persons = new ArrayList<Person>();
        Log.i("SAX", "读取到文档头,开始解析xml");
    }


    /**
     * 读到一个开始标签时调用,第二个参数为标签名,最后一个参数为属性数组
     */
    @Override
    public void startElement(String uri, String localName, String qName,
                             Attributes attributes) throws SAXException {
    
    
        if (localName.equals("person")) {
    
    
            person = new Person();
            person.setId(Integer.parseInt(attributes.getValue("id")));
            Log.i("SAX", "开始处理person元素~");
        }
        this.tagName = localName;
    }


    /**
     * 读到到内容,第一个参数为字符串内容,后面依次为起始位置与长度
     */

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
    
    
        //判断当前标签是否有效
        if (this.tagName != null) {
    
    
            String data = new String(ch, start, length);
            //读取标签中的内容
            if (this.tagName.equals("name")) {
    
    
                this.person.setName(data);
                Log.i("SAX", "处理name元素内容");
            } else if (this.tagName.equals("age")) {
    
    
                this.person.setAge(Integer.parseInt(data));
                Log.i("SAX", "处理age元素内容");
            }

        }

    }

    /**
     * 处理元素结束时触发,这里将对象添加到结合中
     */
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
    
    
        if (localName.equals("person")) {
    
    
            this.persons.add(person);
            person = null;
            Log.i("SAX", "处理person元素结束~");
        }
        this.tagName = null;
    }

    /**
     * 读取到文档结尾时触发,
     */
    @Override
    public void endDocument() throws SAXException {
    
    
        super.endDocument();
        Log.i("SAX", "读取到文档尾,xml解析结束");
    }

    //获取persons集合
    public ArrayList<Person> getPersons() {
    
    
        return persons;
    }

}

然后我们在MainActivity.java中写上如下方法,然后要解析XML的时候调用下 就好了~

private ArrayList<Person> readxmlForSAX() throws Exception {
    
    
    //获取文件资源建立输入流对象
    InputStream is = getAssets().open("person1.xml");
    //①创建XML解析处理器
    SaxHelper ss = new SaxHelper();
    //②得到SAX解析工厂
    SAXParserFactory factory = SAXParserFactory.newInstance();
    //③创建SAX解析器
    SAXParser parser = factory.newSAXParser();
    //④将xml解析处理器分配给解析器,对文档进行解析,将事件发送给处理器
    parser.parse(is, ss);
    is.close();
    return ss.getPersons();
}

person1.xml文件,然后放到assets目录下的

<?xml version="1.0" encoding="UTF-8"?>
<persons>
    <person id = "11">
        <name>SAX解析</name>
        <age>18</age>
    </person>
    <person id = "13">
        <name>XML1</name>
        <age>43</age>
    </person>
</persons>

1.1.2.2 DOM解析XML

先把 XML文档都读到内存中,然后再有DOM
API来访问树形结构并获取数据。这个写起来很简单,但是很消耗内存,加入读取的数据量大,手机内存不够的话可能导致手机死机,不建议在安卓设备中使用解析,简单的XML文件到可以。
常用的五个接口与类:Document,Element,Node,NodeList,DOMParser
DOM是整个文件解析到内存中,供用户需要的节点信息,支持随机访问。

DOM的api:
在这里插入图片描述
核心代码:

DomHelper.java

public class DomHelper {
    
    
    public static ArrayList<Person> queryXML(Context context)
    {
    
    
        ArrayList<Person> Persons = new ArrayList<Person>();
        try {
    
    
            //①获得DOM解析器的工厂示例:
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            //②从Dom工厂中获得dom解析器
            DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
            //③把要解析的xml文件读入Dom解析器
            Document doc = dbBuilder.parse(context.getAssets().open("person2.xml"));
            System.out.println("处理该文档的DomImplemention对象=" + doc.getImplementation());
            //④得到文档中名称为person的元素的结点列表
            NodeList nList = doc.getElementsByTagName("person");
            //⑤遍历该集合,显示集合中的元素以及子元素的名字
            for(int i = 0;i < nList.getLength();i++)
            {
    
    
                //先从Person元素开始解析
                Element personElement = (Element) nList.item(i);
                Person p = new Person();
                p.setId(Integer.valueOf(personElement.getAttribute("id")));

                //获取person下的name和age的Note集合
                NodeList childNoList = personElement.getChildNodes();
                for(int j = 0;j < childNoList.getLength();j++)
                {
    
    
                    Node childNode = childNoList.item(j);
                    //判断子note类型是否为元素Note
                    if(childNode.getNodeType() == Node.ELEMENT_NODE)
                    {
    
    
                        Element childElement = (Element) childNode;
                        if("name".equals(childElement.getNodeName()))
                            p.setName(childElement.getFirstChild().getNodeValue());
                        else if("age".equals(childElement.getNodeName()))
                            p.setAge(Integer.valueOf(childElement.getFirstChild().getNodeValue()));
                    }
                }
                Persons.add(p);
            }
        } catch (Exception e) {
    
    e.printStackTrace();}
        return Persons;
    }
}

从代码我们就可以看出DOM解析XML的流程,先整个文件读入Dom解析器,然后形成一棵树, 然后我们可以遍历节点列表获取我们需要的数据!

1.1.2.3 pull解析XML

XML
pull提供了开始元素和结束元素。当某个元素开始时,我们调用parser.nextText0从XML文档中提取所有字符数据,当解释到一个文档结束时,自动生成EndDocument。常用接口和类:XmlPullParser,XmlSreializer,XmlPullParserFactory
和sax差不多,代码没那么实现较为简单,非常适合移动设备,安卓系统内置pull解析器,而且安卓系统内部默认使用pull来解析XML文件。如果需要在Jay2EE或者其他使用pull需要导入两个包,后面给出下载。

解析文件流程:
在这里插入图片描述
核心代码

public static ArrayList<Person> getPersons(InputStream xml)throws Exception
{
    
    
    //XmlPullParserFactory pullPaser = XmlPullParserFactory.newInstance();
    ArrayList<Person> persons = null;
    Person person = null;
    // 创建一个xml解析的工厂  
    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();  
    // 获得xml解析类的引用  
    XmlPullParser parser = factory.newPullParser();  
    parser.setInput(xml, "UTF-8");  
    // 获得事件的类型  
    int eventType = parser.getEventType();  
    while (eventType != XmlPullParser.END_DOCUMENT) {
    
      
        switch (eventType) {
    
      
        case XmlPullParser.START_DOCUMENT:  
            persons = new ArrayList<Person>();  
            break;  
        case XmlPullParser.START_TAG:  
            if ("person".equals(parser.getName())) {
    
      
                person = new Person();  
                // 取出属性值  
                int id = Integer.parseInt(parser.getAttributeValue(0));  
                person.setId(id);  
            } else if ("name".equals(parser.getName())) {
    
      
                String name = parser.nextText();// 获取该节点的内容  
                person.setName(name);  
            } else if ("age".equals(parser.getName())) {
    
      
                int age = Integer.parseInt(parser.nextText());  
                person.setAge(age);  
            }  
            break;  
        case XmlPullParser.END_TAG:  
            if ("person".equals(parser.getName())) {
    
      
                persons.add(person);  
                person = null;  
            }  
            break;  
        }  
        eventType = parser.next();  
    }  
    return persons;  
}  

使用Pull生成xml数据的流程:
在这里插入图片描述
核心代码:

public static void save(List<Person> persons, OutputStream out) throws Exception {
    
    
    XmlSerializer serializer = Xml.newSerializer();
    serializer.setOutput(out, "UTF-8");
    serializer.startDocument("UTF-8", true);
    serializer.startTag(null, "persons");
    for (Person p : persons) {
    
    
        serializer.startTag(null, "person");
        serializer.attribute(null, "id", p.getId() + "");
        serializer.startTag(null, "name");
        serializer.text(p.getName());
        serializer.endTag(null, "name");
        serializer.startTag(null, "age");
        serializer.text(p.getAge() + "");
        serializer.endTag(null, "age");
        serializer.endTag(null, "person");
    }

    serializer.endTag(null, "persons");
    serializer.endDocument();
    out.flush();
    out.close();
}

2.Json数据解析

JavaScript Object Natation, 一种轻量级的数据交换格式, 与XML一样, 广泛被采用的客户端和服务端交互的解决方案!具有良好的可读和便于快速编写的特性。

2.1 Json概念以及与XML的比较

  • JSON和XML的数据可读性基本相同;

  • JSON和XML同样拥有丰富的解析手段

  • JSON相对于XML来讲,数据的体积小

  • JSON与JavaScript的交互更加方便

  • JSON对数据的描述性比XML较差

  • JSON的速度要远远快于XML

2.2 Json的格式规范

[
    {
    
     "id":"1","name":"基神","age":"18" },
    {
    
     "id":"2","name":"B神","age":"18"  },
    {
    
     "id":"3","name":"曹神","age":"18" }
]

2.3 Json解析类

这些API都存在于org.json包下,而我们用到的类有下面这些:

  • JSONObject: Json对象,可以完成Json字符串与Java对象的相互转换
  • JSONArray: Json数组,可以完成Json字符串与Java集合或对象的相互转换
  • JSONStringer: Json文本构建类,这个类可以帮助快速和便捷的创建JSON text, 每个JSONStringer实体只能对应创建一个JSON text
  • JSONTokener:Json解析类
  • JSONException:Json异常

2.4 案例演示

2.4.1 新建项目

在这里插入图片描述
在这里插入图片描述

2.4.2 添加背景图片

在这里插入图片描述

2.4.3 activity_main.xml

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background"
    android:orientation="vertical"
    android:padding="10dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btnReadJSON"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doReadJSON"
            android:text="@string/read_json"
            android:textSize="20sp" />

        <Button
            android:id="@+id/btnParseJson"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doParseJSON"
            android:text="@string/parse_json"
            android:textSize="20sp" />
    </LinearLayout>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:background="#bbbbbb" />

    <ScrollView
        android:id="@+id/svContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tvContent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#0000ff"
            android:textSize="20sp" />
    </ScrollView>
</LinearLayout>

2.4.4 创建信息文件

将视图切换至project视图,创建assets目录,在里面创建textbook.json
在这里插入图片描述
在这里插入图片描述
将视图切换回Android视图,查看textbook.json文件
在这里插入图片描述

[
  {
    
    
    "id": "1",
    "name": "计算机基础教程",
    "press": "清华大学出版社",
    "author": "李晓云",
    "price": "30.5"
  },
  {
    
    
    "id": "2",
    "name": "Java程序设计",
    "press": "水利水电出版社",
    "author": "张国锋",
    "price": "40"
  },
  {
    
    
    "id": "3",
    "name": "安卓应用开发",
    "press": "北京大学出版社",
    "author": "郑晓华",
    "price": "60.5"
  },
  {
    
    
    "id": "4",
    "name": "PHP应用开发教程",
    "press": "南京大学出版社",
    "author": "滕玉国",
    "price": "27.5"
  }
]

2.4.5 strings.xml

在这里插入图片描述

<resources>
    <string name="app_name">读取解析JSON</string>
    <string name="read_json">读取JSON</string>
    <string name="parse_json">解析JSON</string>
</resources>

2.4.6 MainActivity.java

在这里插入图片描述

package net.nell.readparsejson;

import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {
    
    

    private TextView tvContent; // 显示内容的标签
    private String content; // 文件内容字符串

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        // 利用布局文件设置用户界面
        setContentView(R.layout.activity_main);

        // 通过资源标识获得控件实例
        tvContent = findViewById(R.id.tvContent);
    }

    /**
     * 读取JSON
     *
     * @param view
     */
    public void doReadJSON(View view) {
    
    
        try {
    
    
            // 读取assets目录里的文件,获取字节输入流
            InputStream is = getResources().getAssets().open("textbook.json");
            // 获取字节输入流长度
            int length = is.available();
            // 定义字节缓冲区
            byte[] buffer = new byte[length];
            // 读取字节输入流,将数据保存在字节缓冲区里
            is.read(buffer);
            // 将字节缓冲区的数据转换成字符串
            content =new String(buffer, "utf-8");
            // 将字符串显示在标签里
            tvContent.setText(content);
            // 设置标签的文本颜色
            tvContent.setTextColor(Color.BLUE);
            // 关闭字节输入流
            is.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 解析JSON
     *
     * @param view
     */
    public void doParseJSON(View view) {
    
    
        // 判断用户是否先读取了JSON
        if (content == null) {
    
    
            Toast.makeText(this, "请先读取JSON!", Toast.LENGTH_LONG).show();
        } else {
    
    
            try {
    
    
                // 清空标签内容
                tvContent.setText("");
                // 创建Json数组
                JSONArray jsonArray = new JSONArray(content);
                // 遍历Json数组
                for (int i = 0; i < jsonArray.length(); i++) {
    
    
                    // 获取Json对象
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    // 对于Json对象按键取值
                    String id = jsonObject.getString("id");
                    String name = jsonObject.getString("name");
                    String press = jsonObject.getString("press");
                    String author = jsonObject.getString("author");
                    String price = jsonObject.getString("price");
                    // 拼接成一个图书信息
                    String book = "编号:" + id + "\n书名:《" + name + "》\n出版社:" + press + "\n作者:" + author + "\n单价:" + price + "\n\n";
                    // 将图书信息添加到标签里
                    tvContent.append(book);
                    // 设置标签的文本颜色
                    tvContent.setTextColor(Color.RED);
                }
            } catch (JSONException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

2.4.7 启动程序,查看效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46705517/article/details/113046331