xml几种解析

作者: 的一幕 | 来源:发表于2019-08-08 16:24 被阅读12次

    xml解析方式一般分为三种解析方式,下面通过一段xml,使用三种方式解析,首先来看下要解析的xml:

    <simple>
        <paragraph>
            <text content="北京市,简称“" />
            <text content="京" link="https://baike.baidu.com/item/京/15808773" />
            <text content="”,是中华人民共和国省级行政区、" />
            <text content="首都" link="https://baike.baidu.com/item/首都/26194" />
            <text content="、" />
            <text content="直辖市" link="https://baike.baidu.com/item/直辖市/725471" />
            <text content="国家中心城市" link="https://baike.baidu.com/item/国家中心城市/842500" />
            <text content="、超大城市,全国" />
            <text content="政治中心" link="https://baike.baidu.com/item/政治中心/3218495" />
            <text content="、文化中心、国际交往中心、科技创新中心,是世界著名古都和现代化国际城市,是" />
            <text content="中国共产党中央委员会" link="https://baike.baidu.com/item/中国共产党中央委员会/1141242" />
            <text content="、" />
            <text content="中华人民共和国中央人民政府" link="https://baike.baidu.com/item/中华人民共和国中央人民政府/5693897" />
            <text content="和全国人民代表大会常务委员会的办公所在地。" />
        </paragraph>
    
        <paragraph>
            <text content="北京地处中国华北地区,中心位于东经" />
            <text strong="116°20′" />
            <text content="北纬" />
            <text strong="39°56′" />
            <text content="东与" />
            <text content="天津" link="https://baike.baidu.com/item/天津/132308" />
            <text content="毗连,其余均与" />
            <text content="河北" link="https://baike.baidu.com/item/河北/65777" />
            <text content="相邻,北京市总面积" />
            <text strong="16410.54" />
            <text content="平方千米。截至" />
            <text strong="2017" />
            <text content="年底,北京市下辖" />
            <text strong="16" />
            <text content="个市辖区。" />
        </paragraph>
    </simple>
    

    这是两个段落的语句,最终解析完成后,需要通过textview的span显示在textview上面:


    image.png

    标签分别有content、strong、link等内容,为了实现三种xml解析方式,这里写了个简单的工厂模式:


    image.png
    分别对应了pull、dom、sax解析方式。
    • pull解析,pull解析是拿到每一个标签,是并行解析,然后每拿到一个解析的标签触发到XmlPullParser.START_TAG,解析完了该标签后触发XmlPullParser.END_TAG,通过XmlPullParser.getEventType可以拿到是标签的开始,还是结束,还是整个xml的结束,XmlPullParser.next可以知道是不是xml结束,XmlPullParser.getDepth可以知道当前标签是嵌套了几层,一般被称为标签深度。其中pull解析现在用得多的org.xmlpull.v1.XmlPullParserFactory来创建XmlPullParser,还有种方式是通过Xml.newPullParser来创建。
    public class PullParse implements Parse {
        @Override
        public List<Paragraph> parse(InputStream is) throws Exception {
            List<Paragraph> paragraphs = null;
            Paragraph paragraph =p null;
            Text tag = null;
            //创建xmlPull解析器
            //org.xmlpull.v1解析方式
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            //区分namespace
            factory.setNamespaceAware(true);
            XmlPullParser parser = factory.newPullParser();
            //传统的xml解析方式
            XmlPullParser parser1 = Xml.newPullParser();
            ///初始化xmlPull解析器
            parser.setInput(is, "utf-8");
            //读取文件的类型
            int type = parser.getEventType();
            //对应当前节点的深度
            int startDepth = parser.getDepth();
            Log.d("PullParse", "startDepth:" + startDepth);
            //无限判断文件类型进行读取
            //pull解析是按照节点的start_tag和end_tag来解析,在遍历的时候通过判断是不是到了节点的结尾
            while (type != XmlPullParser.END_DOCUMENT) {
                switch (type) {
                    //开始标签
                    case XmlPullParser.START_TAG:
                        if ("simple".equals(parser.getName())) {
                            paragraphs = new ArrayList<>();
                            int simpleDepth = parser.getDepth();
                            Log.d("PullParse", "simpleDepth:" + simpleDepth);
                        } else if ("paragraph".equals(parser.getName())) {
                            paragraph = new Paragraph();
                            int paragraphDepth = parser.getDepth();
                            Log.d("PullParse", "paragraphDepth:" + paragraphDepth);
                        } else if ("text".equals(parser.getName())) {
                            tag = new Text();
                            int textDepth = parser.getDepth();
                            Log.d("PullParse", "textDepth:" + textDepth);
                            String link = parser.getAttributeValue(null, "link");
                            String content = parser.getAttributeValue(null, "content");
                            String strong = parser.getAttributeValue(null, "strong");
                            tag.link = link;
                            tag.content = content;
                            tag.strong = strong;
                        }
                        break;
                    //结束标签
                    case XmlPullParser.END_TAG:
                        if ("text".equals(parser.getName())) {
                            paragraph.tags.add(tag);
                        } else if ("paragraph".equals(parser.getName())) {
                            paragraphs.add(paragraph);
                        }
                        break;
                }
                //继续往下读取标签类型
                type = parser.next();
            }
            return paragraphs;
        }
    }
    
    image.png
    • dom解析,该种解析首先拿到整个xml的直接子节点,例子中的子节点是paragraph,然后里面可以通过Node.getChildNodes方式获取到NodeList
      Node.getNamedItem可以获取到标签里面的内容:
    public class DomParse implements Parse {
        @Override
        public List<Paragraph> parse(InputStream is) throws Exception {
            List<Paragraph> list = new ArrayList<>();
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(is);
            //dom解析首先是获取到当前有几个直接的子节点
            NodeList studentList = document.getElementsByTagName("paragraph");
            for (int i = 0; i < studentList.getLength(); i++) {
                Node node_student = studentList.item(i);
                NodeList childNodes = node_student.getChildNodes();
                Paragraph student = new Paragraph();
                for (int j = 0; j < childNodes.getLength(); j++) {
                    Node childNode = childNodes.item(j);
                    if ("text".equals(childNode.getNodeName())) {
                        Text text = new Text();
                        NamedNodeMap nnm = childNode.getAttributes();
                        Node linkNode = nnm.getNamedItem("link");
                        Node contentNode = nnm.getNamedItem("content");
                        Node strongNode = nnm.getNamedItem("strong");
                        if (linkNode != null && !TextUtils.isEmpty(linkNode.getTextContent())) {
                            text.link = linkNode.getTextContent();
                        }
                        if (contentNode != null && !TextUtils.isEmpty(contentNode.getTextContent())) {
                            text.content = contentNode.getTextContent();
                        }
                        if (strongNode != null && !TextUtils.isEmpty(strongNode.getTextContent())) {
                            text.strong = strongNode.getTextContent();
                        }
                        student.tags.add(text);
                    }
                }
                //加到List中
                list.add(student);
            }
            return list;
        }
    }
    
    • sax解析有点像pull解析,也是并行解析的,解析的时候会触发到startElementendElement等方法。
    public class SaxParse implements Parse {
        @Override
        public List<Paragraph> parse(InputStream is) throws Exception {
            SAXParserFactory spf = SAXParserFactory.newInstance();
            //初始化Sax解析器
            SAXParser sp = spf.newSAXParser();
            //新建解析处理器
            MyHandler handler = new MyHandler();
            //将解析交给处理器
            sp.parse(is, handler);
            //返回List
            return handler.getList();
        }
    
        public static class MyHandler extends DefaultHandler {
    
            private List<Paragraph> list;
            private Paragraph paragraph;
            Text text;
    
            /**
             * 解析到文档开始调用,一般做初始化操作
             *
             * @throws SAXException
             */
            @Override
            public void startDocument() throws SAXException {
                list = new ArrayList<>();
                super.startDocument();
            }
    
            /**
             * 解析到文档末尾调用,一般做回收操作
             *
             * @throws SAXException
             */
            @Override
            public void endDocument() throws SAXException {
                super.endDocument();
            }
    
            /**
             * 每读到一个元素就调用该方法
             *
             * @param uri
             * @param localName
             * @param qName
             * @param attributes
             * @throws SAXException
             */
            @Override
            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                if ("text".equals(qName)) {
                    //读到student标签
                    text = new Text();
                    text.link = attributes.getValue("link");
                    text.strong = attributes.getValue("strong");
                    text.content = attributes.getValue("content");
                } else if ("paragraph".equals(qName)) {
                    paragraph = new Paragraph();
                }
                super.startElement(uri, localName, qName, attributes);
            }
    
            /**
             * 读到元素的结尾调用
             *
             * @param uri
             * @param localName
             * @param qName
             * @throws SAXException
             */
            @Override
            public void endElement(String uri, String localName, String qName) throws SAXException {
                if ("text".equals(qName)) {
                    paragraph.tags.add(text);
                } else if ("paragraph".equals(qName)) {
                    list.add(paragraph);
                }
                super.endElement(uri, localName, qName);
            }
    
            /**
             * 读到属性内容调用
             *
             * @param ch
             * @param start
             * @param length
             * @throws SAXException
             */
            @Override
            public void characters(char[] ch, int start, int length) throws SAXException {
                super.characters(ch, start, length);
            }
    
            /**
             * 获取该List
             *
             * @return
             */
            public List<Paragraph> getList() {
                return list;
            }
        }
    }
    

    好了,几种解析方式就介绍到这里,在解析之后,还需要掌握textview各种span的设置。常用的有ForegroundColorSpan:设置部分文字颜色的spanClickableSpan:部分文字点击的spanStyleSpan:可以设置粗体的span,关于stylespan其他的样式大家可以尝试
    完整demo点这里

    相关文章

      网友评论

        本文标题:xml几种解析

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