4--安卓网络编程之XML总汇篇

作者: e4e52c116681 | 来源:发表于2018-10-17 16:56 被阅读2次

    零、前言

    Xml是一种应用广泛的标记语言,我们常见的html便是它的子集。形如:<XXX>xxx</XXX>组成的闭合标签
    安卓的res目录下的xml想必大家都是否熟悉,它们最终都是在代码中被读取并解析发挥效果的
    安卓的SharedPreferences是以Xml的形式存储数据的,就连AndroidManifest注意一看也是Xml
    可以说xml涉及到了安卓的很多方面,我们并不陌生,Xml最大的好处就是解耦,容易复用和更换

    pull解析.png
    XML常见的三种解析方式:
    解析方式 加载驱动方式 可修改? 自定义结束? 效率 备注
    Pull解析 事件驱动 安卓专有
    Sax解析 事件驱动
    Dom解析 直接全部加载 解析时构建dom树
    准备的待解析xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <weapons>
        <weapon material="玉" type="剑">
            <name>问天剑</name>
            <atk>2000</atk>
            <user>语熙华</user>
        </weapon>
        <weapon material="铁" type="刀">
            <name>皇刀</name>
            <atk>3000</atk>
            <user>九方玄玉</user>
        </weapon>
    </weapons>
    

    一、Pull解析概述

    Pull是安卓内置的,基于事件触发的解析器
    Pull解析器小巧轻便,解析速度快,简单易用
    主动从解析器中获取事件,可以在满足了需要的条件后不再获取事件,结束解析
    
    1、Pull解析Xml:
    private ArrayList<WeaponXml> parseXmlWithPull() {
        InputStream is = null;
        try {
            //XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            //XmlPullParser pullParser = factory.newPullParser();
            //获得Xml解析器--等价上两句
            XmlPullParser pullParser = Xml.newPullParser();
            //得到一个含有xml的is输入流
             is = getAssets().open("weapon.xml");
            //设置输入流
            pullParser.setInput(is, "utf-8");
            //触发第一个事件:eventType=0 即:START_DOCUMENT
            int eventType = pullParser.getEventType();
            //没有读到文档结束之前都在while里走
            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {//根据事件类型执行
                    case XmlPullParser.START_DOCUMENT://文档开始
                        //新建对象的集合
                        mWeapons = new ArrayList<>();
                        break;
                    case XmlPullParser.START_TAG://读到第一个标签时再进行switch选择
                        switch (pullParser.getName()) {//拿到标签名称
                            case "weapon"://如果标签是weapon
                                //新建一个 Weapon对象用来记录信息
                                mWeapon = new WeaponXml();
                                //获取第一个属性值
                                String material = pullParser.getAttributeValue(0);
                                //获取第二个属性值
                                String type = pullParser.getAttributeValue(1);
                                //对象装载得到的属性
                                mWeapon.setType(type);
                                mWeapon.setMaterial(material);
                                break;
                            case "name":
                                //对于没有属性的标签,可以用nextText获取标签内部的文字
                                String name = pullParser.nextText();
                                mWeapon.setName(name);
                                break;
                            case "atk":
                                Short atk = new Short(pullParser.nextText());
                                mWeapon.setAtk(atk);
                                break;
                            case "user":
                                String user = pullParser.nextText();
                                mWeapon.setUser(user);
                                break;
                        }
                        break;
                    case XmlPullParser.END_TAG://当事件类型是终止标签时:即</XXX>
                        if ("weapon".equals(pullParser.getName())) {
                            mWeapons.add(mWeapon);//将生成对象加入集合,一个
                        }
                        break;
                }
                eventType = pullParser.next();//解析下一元素,更新event
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (is != null) {
                try {
                    is.close();//关流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return mWeapons;
    }
    
    2、Pull写入Xml:
        /**
         * 备份Xml--当然也可以备份任意的实体类作为Xml,比如短信,联系人
         */
        private void backUpXml() {
            ArrayList<WeaponXml> weapons = parseXmlWithPull();
            XmlSerializer serializer = Xml.newSerializer();
            FileOutputStream fos = null;
            try {
                String path = Environment.getExternalStorageDirectory().getAbsolutePath();
                 fos = new FileOutputStream(path + File.separator + "weapon.xml");
    
                serializer.setOutput(fos, "utf-8");
                //文档开始
                serializer.startDocument("utf-8", true);
                serializer.startTag("", "weapons");
                for (WeaponXml weapon : weapons) {
                    //新建标签: <weapon>
                    serializer.startTag(null, "weapon");
                    //设置属性: material="玉" type="剑"
    
                    serializer.attribute("","material", weapon.getMaterial());
                    serializer.attribute("","type", weapon.getType());
                    //嵌套子标签:<name>问天剑</name>
                    serializer.startTag(null, "name");
                    serializer.text(weapon.getName().trim());
                    serializer.endTag(null, "name");
    
                    serializer.startTag(null, "atk");
                    serializer.text(weapon.getAtk() + "");
                    serializer.endTag(null, "atk");
    
                    serializer.startTag(null, "user");
                    serializer.text(weapon.getUser().trim());
                    serializer.endTag(null, "user");
                    //终止标签: </weapon>
                    serializer.endTag(null, "weapon");
                }
                serializer.endTag("", "weapons");//标签结束
                serializer.endDocument();//文档结束
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
    

    二、Sax解析概述:(Simple API for XML)

    Sax解析方式会逐行地去扫描XML文档,当遇到标签时会触发解析处理器,采用事件处理的方式解析XML 
    优点:在读取文档的同时即可对XML进行处理,不必等到文档加载结束,相对快捷,所以可以解析超大XML
    缺点:只能用来读取XML中数据,无法进行增删改。
    
    1、Sax解析Xml
    /**
     * 
     * @return
     */
    private ArrayList<WeaponXml> parseXmlWithSax() {
        InputStream is = null;
        mWeapons = new ArrayList<>();
        try {
            SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
            is = getAssets().open("weapon.xml");
            saxParser.parse(is, new DefaultHandler() {
                /**
                 *  开始标签时
                 * @param uri 命名空间
                 * @param localName 标签名
                 * @param qName 全名(带命名空间的标签的名字)
                 * @param attributes 属性
                 * @throws SAXException
                 */
                @Override
                public void startElement(String uri, String localName,
                                         String qName, Attributes attributes) throws SAXException {
                    //"属性名:" + attributes.getLocalName(i)
                    //"属性值:" + attributes.getValue(i));
                    if ("weapon".equals(localName)) {
                        mWeapon = new WeaponXml();
                        mWeapon.setMaterial(attributes.getValue(0));
                        mWeapon.setType(attributes.getValue(1));
                    }
                    mPerTag = localName;
                }
                /**解析标签的内容的时候调用
                 *
                 * @param ch 当前文本节点的字节数组
                 * @param start 字节开始的位置 默认 0 全部读取
                 * @param length 长度
                 * @throws SAXException
                 */
                @Override
                public void characters(char[] ch, int start, int length) throws SAXException {
                    String chars = new String(ch, start, length).trim();
                    if ("name".equals(mPerTag)) {
                        mWeapon.setName(chars);
                    } else if ("atk".equals(mPerTag)) {
                        mWeapon.setAtk(Integer.parseInt(chars));
                    } else if ("user".equals(mPerTag)) {
                        mWeapon.setUser(chars);
                    }
                }
                /**
                 * 标签解析结束调用
                 * @param uri
                 * @param localName
                 * @param qName
                 * @throws SAXException
                 */
                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    if ("weapon".equals(localName)) {
                        mWeapons.add(mWeapon);
                        mWeapon = null;
                    }
                    mPerTag = null;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return mWeapons;
    }
    

    2、Sax存储Xml
    /**
     * sax创建Xml文件
     */
    private void saxCreateXml() {
        ArrayList<WeaponXml> weaponXmls = parseXmlWithSax();
        //1、创建一个SAXTransformerFactory的对象
        SAXTransformerFactory saxTF = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
        FileOutputStream fos = null;
        try {
            //创建一个Transformer对象
            TransformerHandler handler = saxTF.newTransformerHandler();
            Transformer transformer = handler.getTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            String path = Environment.getExternalStorageDirectory().getAbsolutePath();
            fos = new FileOutputStream(path + File.separator + "weaponSax.xml");
            StreamResult result = new StreamResult(fos);
            handler.setResult(result);
            //开始
            handler.startDocument();
            AttributesImpl atts = new AttributesImpl();
            handler.startElement("", "", "weapons", atts);
            for (WeaponXml weaponXml : weaponXmls) {
                atts.clear();
                atts.addAttribute("", "", "material", "", weaponXml.getMaterial());
                atts.addAttribute("", "", "type", "", weaponXml.getType());
                handler.startElement("", "", "weapon", atts);
                atts.clear();
                handler.startElement("", "", "name", atts);
                handler.characters(weaponXml.getName().toCharArray(), 0, weaponXml.getName().length());
                handler.endElement("", "", "name");
                atts.clear();
                handler.startElement("", "", "atk", atts);
                String atk = String.valueOf(weaponXml.getAtk());
                handler.characters(atk.toCharArray(), 0, atk.length());
                handler.endElement("", "", "atk");
                atts.clear();
                handler.startElement("", "", "user", atts);
                handler.characters(weaponXml.getUser().toCharArray(), 0, weaponXml.getUser().length());
                handler.endElement("", "", "user");
                handler.endElement("", "", "weapon");
            }
            handler.endElement("", "", "weapons");
            //关闭document
            handler.endDocument();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    三、DOM解析概述:

    DOM将整个XML文件加载到内存中,并构建出节点树;
    应用程序可以通过遍历节点树的方式来解析XML文件中的各个节点、属性等信息;
    优点:对XML节点的添加修改等,而且解析也很方便
    缺点比较耗费内存,解析速度也不快
    
    1、dom解析Xml
        /**
         * dom解析Xml
         * @return
         */
        private ArrayList<WeaponXml> parseXmlWithDom() {
             mWeapons = new ArrayList<>();
            InputStream is = null;
    
            try {
                is = getAssets().open("weapon.xml");
                //获取document对象
                Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
                //获取根元素
                Element root = dom.getDocumentElement();
                //获取weapon节点
                NodeList weaponNode = root.getElementsByTagName("weapon");
                for (int i = 0; i < weaponNode.getLength(); i++) {
                    mWeapon = new WeaponXml();
                    //获取person下第i个元素
                    Element weaponEl = (Element) weaponNode.item(i);
                    String material = weaponEl.getAttribute("material");//得到第i个属性值
                    String type = weaponEl.getAttribute("type");//得到第i个属性值
    
                    mWeapon.setMaterial(material);
                    mWeapon.setType(type);
    
                    NodeList childNodes = weaponEl.getChildNodes();//获得获取weapon下子元素
    
                    for (int j = 0; j < childNodes.getLength(); j++) {
    
                        if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE) {
                            String nodeName = childNodes.item(j).getNodeName();
                            if ("name".equals(nodeName)) {
                                String name = childNodes.item(j).getFirstChild().getNodeValue();
                                mWeapon.setName(name);
                            } else if ("atk".equals(nodeName)) {
                                String atk = childNodes.item(j).getFirstChild().getNodeValue();
                                mWeapon.setAtk(Integer.parseInt(atk));
                            } else if ("user".equals(nodeName)) {
                                String user = childNodes.item(j).getFirstChild().getNodeValue();
                                mWeapon.setUser(user);
                            }
                        }
                    }
                    mWeapons.add(mWeapon);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return mWeapons;
        }
    

    2、dom存储Xml
        /**
         * sax创建Xml文件
         */
        private void domCreateXml() {
            try {
                ArrayList<WeaponXml> weaponXmls = parseXmlWithDom();
    
                //创建Dom解析器
                DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    
                //新建空白文档
                Document doc = builder.newDocument();
                //建立根元素employees
                Element root = doc.createElement("weapons");
                //将根节点添加进入文档
                doc.appendChild(root);
    
                for (WeaponXml weaponXml : weaponXmls) {
                    Element weapon = doc.createElement("weapon");
                    weapon.setAttribute("material", weaponXml.getMaterial());
                    weapon.setAttribute("type", weaponXml.getType());
                    root.appendChild(weapon);
    
                    Element name = doc.createElement("name");
                    name.appendChild(doc.createTextNode(weaponXml.getName()));
                    weapon.appendChild(name);
    
    
                    Element atk = doc.createElement("atk");
                    atk.appendChild(doc.createTextNode(weaponXml.getAtk()+""));
                    weapon.appendChild(atk);
    
                    Element user = doc.createElement("user");
                    user.appendChild(doc.createTextNode(weaponXml.getUser()));
                    weapon.appendChild(user);
                }
    
                //为了得到xslt引擎创建对象
                TransformerFactory tff = TransformerFactory.newInstance();
                //创建xslt引擎对象输出xml文档
                Transformer tf = tff.newTransformer();
                //获取属性对象
                Properties pro = tf.getOutputProperties();
                //设置编码格式和输出格式
                pro.setProperty(OutputKeys.ENCODING, "utf-8");
                pro.setProperty(OutputKeys.METHOD, "xml");
                tf.setOutputProperties(pro);
                //创建资源对象
                DOMSource source = new DOMSource(doc);
                String path = Environment.getExternalStorageDirectory().getAbsolutePath()
                        +File.separator+"WeaponDom.xml";
                //获得输出对象
                StreamResult result = new StreamResult(new File(path));
                //执行dom文档到xml文件转换
                tf.transform(source, result);
            } catch (Exception e) {
                e.printStackTrace();
            }
    


    后记:捷文规范

    1.本文成长记录及勘误表
    项目源码 日期 备注
    V0.1--无 2018-10-15 4--安卓网络编程之XML总汇篇
    2.更多关于我
    笔名 QQ 微信 爱好
    张风捷特烈 1981462002 zdl1994328 语言
    我的github 我的简书 我的CSDN 个人网站
    3.声明

    1----本文由张风捷特烈原创,转载请注明
    2----欢迎广大编程爱好者共同交流
    3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
    4----看到这里,我在此感谢你的喜欢与支持

    相关文章

      网友评论

        本文标题:4--安卓网络编程之XML总汇篇

        本文链接:https://www.haomeiwen.com/subject/aqprzftx.html