xml 文件解析的 3 种方式

xml 是数据传输的一种格式,Android 中的布局文件、设置文件等都采用它来表示。Android 中对 xml 文件的解析也有多种方式,下面介绍常用的 3 种方式: Dom 、 SAX 和 dom4j。

先看一个简单的 xml 文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <书 出版社="骏马">
        <书名>如何成功</书名>
        <作者>uniapp</作者>
        <售价>666</售价>
    </书>
    <书>
        <书名>如何成功1</书名>
        <作者>uniapp</作者>
        <售价>1991</售价>
    </书>
</书架>
1 Dom解析方式

Dom 解析通过 Document 类将整个 xml 文件一次读入内存,然后通过操作 Document 实例的属性实现对 xml 文件中元素的增删改查,具体代码如下:

/**
     * 查看所有元素名称
     * */
    private void printAllElement(Node node){
        if (Node.ELEMENT_NODE==node.getNodeType()){
            System.out.println(node.getNodeName());
        }
        NodeList ns = node.getChildNodes();
        for (int i = 0; i < ns.getLength(); i++) {
            node = ns.item(i);
            printAllElement(node);
        }
    }

    /**
     * 更新元素
     * */
    private void updateElement() throws ParserConfigurationException, SAXException, IOException, TransformerException {
        Document doc = getDocument();
        NodeList ns = doc.getElementsByTagName("售价");
        Element el = (Element) ns.item(0);
        el.setTextContent("666");
        writeBackToXml(doc);
    }

    /**
     * 删除节点
     * */
    private void deleteElement() throws ParserConfigurationException, SAXException, IOException, TransformerException {
        Document doc = getDocument();
        NodeList ns = doc.getElementsByTagName("售价");
        for (int i = 0; i < ns.getLength(); i++) {
            Node node = ns.item(i);
            if ("111".equals(node.getTextContent())){
                node.getParentNode().removeChild(node);
            }

        }
        writeBackToXml(doc);
    }
    /**
     * 插入元素节点
     * */
    private void addElement() throws ParserConfigurationException, SAXException, IOException, TransformerException {
        Document doc = getDocument();
        NodeList nl = doc.getElementsByTagName("书");
        int l = nl.getLength();
        System.out.print("\n长度" + l + "\n");
        Node n = nl.item(0);
        Element element = doc.createElement("售价");
        element.setTextContent("888");
        n.appendChild(element);
        writeBackToXml(doc);
    }
    /**
     * 将 Doc 写入新文件
     * */
    private void writeBackToXml(Document doc) throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer =  factory.newTransformer();
        transformer.transform(new DOMSource(doc), new StreamResult("./app/src/main/java/test/DTD.xml"));
    }
/**
     * 获取 Doc 对象
     * */
    private Document getDocument() throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder build = factory.newDocumentBuilder();
        Document document = build.parse("./app/src/main/java/test/DTD.xml");
        return document;
    }
2 SAX解析

SAX 对 xml 文件采用边读边解析的方式,就像我们用眼睛读文章一样,一行一行的进行。相比 Dom 方式产生的瞬时内存峰值,SAX 对内存的消耗比较平稳。它通过解析类提供对外接口,具体实现:

public class SaxDemo {
    @Test
    public void main() throws ParserConfigurationException, SAXException, IOException{
        //工厂类实例
        SAXParserFactory fac =  SAXParserFactory.newInstance();
        //创建解析器
        SAXParser parser =  fac.newSAXParser();
        //解析文档
        XMLReader reader = parser.getXMLReader();
        reader.setContentHandler(new MyDefultHandle());
        reader.parse("./app/src/main/java/test/DTD.xml");

    }
}

class MyDefultHandle extends DefaultHandler{

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();

        System.out.println("文档开始");
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("文档结束");
    }

    private boolean isPrice = false;
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        System.out.println("元素开始: " + qName);

    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);

        if ("售价".equals(qName)){
            isPrice = false;
        }
        System.out.println("元素结束: " + qName);

    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        if (isPrice){
            System.out.println("内容: " + new String(ch, start, length));
        }
    }
}
3 Dom4j 解析

Dom4j 解析是第三开源库给出的解析方式,结合了 Dom 和 SAX 双方的优点,对 xml 文件逐步读入内存,并且可以采用面向对象的方式访问节点。代码如下:

/**
     * 读取属性值
     * */
    public void readAttr() throws DocumentException {
        Document doc = getDocument();
        List<Element> list = doc.getRootElement().elements("书");
        for (int i = 0; i < list.size(); i++) {
            Element el = (Element) list.get(i);
            Attribute att = el.attribute("出版社");
            System.out.print("结果: " + att.getName() + att.getValue());
        }
    }

    /**
     * 读取节点
     * */
    public void read() throws DocumentException {
        /**
         * 不能越级获取值
         * */
        Document doc = getDocument();
        org.dom4j.Element el = doc.getRootElement();
        Element firstEl = el.element("书");
        Element firstBookEl = firstEl.element("书名");

        String name = firstBookEl.getText();
        System.out.println("书名: " + name);
    }

    public void update() throws DocumentException, IOException {
        Document doc = getDocument();
        List<Element> list = doc.getRootElement().elements("书");
        Element element = list.get(0);
        Element priceEl = element.element("售价");
        priceEl.setText("888元");
        XMLWriter writer = new XMLWriter(new FileOutputStream("./app/src/main/java/test/Dom4j3.xml"));
        writer.write(doc);
    }

    /**
     * 删除节点
     * */
    public void deletePrice() throws Exception{
        SAXReader reader = new SAXReader();
        Document doc = reader.read("./app/src/main/java/test/Dom4j1.xml");
        Element el = (Element) doc.getRootElement().elements("书").get(1);
        Element elPrice = (Element) el.elements("售价").get(1);
        elPrice.getParent().remove(elPrice);
        XMLWriter writer = new XMLWriter(new FileOutputStream("./app/src/main/java/test/Dom4j2.xml"));
        writer.write(doc);
        writer.close();
    }
    /**
     * 增加节点
     * */
    public void  addEl() throws DocumentException, IOException {
        Document doc = getDocument();
        Element el = (Element) doc.getRootElement().elements("书").get(1);
        el.addElement("售价").setText("6.66元");
        XMLWriter writer = new XMLWriter(new FileOutputStream("./app/src/main/java/test/Dom4j1.xml"));
        writer.write(doc);
        writer.close();
    }

    private Document getDocument() throws DocumentException {
        SAXReader reader = new SAXReader();
        return reader.read("./app/src/main/java/test/DTD.xml");
    }

结合以上三种解析方式的特点,我们可以得出结论:如果 xml 文件很小,可以选择面向对象的 Dom 或者 dom4j 方式;反之可以选择 SAX 方式,一面实际内存不足造成闪退。

喜欢和关注都是对我的鼓励和支持~
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容