XML的解析

目标是解析一个xml文件:

因为解析XML是很重要的技能:比如微信公众号的后台开发、spring的原理、android的xml系统流程解析布局等。

skill写成了kill,手动滑稽~

xml有2种解析方式:

  • dom解析(w3c标准解析方法,但是效率低。文档dom树,子节点又有小节点。开辟内存空间把整个dom树弄进来。如果文档大,则dom树占用的内存消耗很大。且如果只要解析一个节点,全部装到内存就浪费了)
  • SAX解析(解决dom弊端。扫描开头和结束标签,触发相应的事件,事件驱动【开始结束自动触发】,只拿要用的一部分节点)

这里值得说明的是,很多时候报空指针:

是需要注意,像上方的"尹磊",和其他name、price、kill都属于meimei的子节点。

空格和回车都属于子节点。都属于文字。

所以需要排除文字形式的,只讨论标签形式的。


dom解析

1. 准备实体类,根据上图,可以看到相同的属性加一个meimei标签构成了一个实体类:

属性和标签对应:

2. 编写解析逻辑:(从DocumentBuilderFactory入手)

package com.yinlei.xmlparse;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class XMLUtils {

    public static List<MeiMei> parseXMLToList(String fileName) throws ParserConfigurationException, IOException, SAXException {
        List<MeiMei> meimeis = new ArrayList<>();

        // DOM方式解析: 入口
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//产生DOM工厂实例

        // 造东西
        DocumentBuilder builder = factory.newDocumentBuilder();

        // 准备输入流,parse()需要


        // 解析成一个可以用java处理的document对象
        Document document = builder.parse(new FileInputStream(fileName));
        // 获取所有文档的节点
        Element element = document.getDocumentElement();
        // 获取<meimei>这个节点,得到节点的集合
        NodeList nodeList = element.getElementsByTagName("meimei");
        // 遍历nodelist
        for (int i = 0; i < nodeList.getLength(); i++) {
            MeiMei meimei = new MeiMei();
            //  Node item = nodeList.item(i);// 获取每个<meimei>
            Element meimeiElement = (Element)nodeList.item(i);// 获取每个<meimei>
            // 获取meimei的id属性
            // tem.getAttributes()[0];
            int id = Integer.parseInt(meimeiElement.getAttribute("id"));
            meimei.setId(id);
            //拿<meimei>的子节点<name>、<price><kill>
            NodeList childNodes = meimeiElement.getChildNodes();
            // 遍历子节点
            for (int j=0;j<childNodes.getLength();j++){
                // 每一个子节点<name> <price> <kill> ,也有可能是空格或文字
                Node meimeiChild = childNodes.item(j);
                //只拿标签形式的子节点
                if (meimeiChild.getNodeType() == Node.ELEMENT_NODE) {
                    switch (meimeiChild.getNodeName()){//拿到标签名
                        case "name":
                            String name = meimeiChild.getFirstChild().getNodeValue();
                            meimei.setName(name);
                            break;
                        case "price":
                            String price = meimeiChild.getFirstChild().getNodeValue();
                            meimei.setPrice(Integer.parseInt(price));
                            break;
                        case "kill":
                            String kill = meimeiChild.getFirstChild().getNodeValue();
                            meimei.setKill(kill);
                            break;
                        default:
                            break;
                    }
                }
            }
            meimeis.add(meimei);
        }

        return meimeis;
    }
}

 


SAX解析

事件驱动:程序执行时,到哪个阶段时,自动触发那个阶段的方法。如web中的ajax

1.还是需要实体类:上面的实体类。

2. 解析:(通过sax的处理器来完成DefaultHandler)

package com.yinlei.xmlparse;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.util.ArrayList;
import java.util.List;

/**
 * sax解析
 */
public class SAXParseXML extends DefaultHandler {



    private List<MeiMei> meimeis = null;

    public List<MeiMei> getMeimeis() {
        return meimeis;
    }

    // 元素的名字
    private String tagName;
    private MeiMei meiMei;

    /**
     * 解析xml开始(执行一次)
     * @throws SAXException
     */
    @Override
    public void startDocument() throws SAXException {
        meimeis = new ArrayList<>();
    }

    /**
     * 解析xml结束(执行一次)
     * @throws SAXException
     */
    @Override
    public void endDocument() throws SAXException {
        System.out.println("SAX解析结束。。");
    }

    /**
     * 解析元素开始(执行多次)
     * <name>
     *     yinlei
     * </name>
     * 这里的yinlei不在标签里,在characters()里才能拿到。
     * @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 (qName.equals("meimei")) {
            meiMei = new MeiMei();
            int id = Integer.parseInt(attributes.getValue(0));
            meiMei.setId(id);
        }
        this.tagName = qName;
    }

    /**
     * 解析元素结束(执行多次)
     * @param uri
     * @param localName
     * @param qName
     * @throws SAXException
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (qName.equals("meimei")){
            meimeis.add(meiMei);
        }
        this.tagName = null;
    }

    /**
     * 开始解析元素和结束解析元素之间调用多次.
     * 拿中间真正的值
     * 比如拿<name>yinlei</name>
     * 就可以拿到yinlei
     * @param ch 里面是要解析的值,自动放在了这里面。
     * @param start
     * @param length
     * @throws SAXException
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (this.tagName != null) {
            String data = new String(ch,start,length);//ch()=>String
            if (this.tagName.equals("name")) {
                //name
                meiMei.setName(data);
            }
            if (this.tagName.equals("price")) {
                //price
                meiMei.setPrice(Integer.parseInt(data));
            }
            if (this.tagName.equals("kill")) {
                //kill
                meiMei.setKill(data);
            }
        }
    }
}

3. 使用:

package com.yinlei.xmlparse;

import com.sun.org.apache.xml.internal.resolver.readers.SAXParserHandler;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * xml解析
 */
public class Demo {
    public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
        SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
        InputStream in = new FileInputStream("C:\\Users\\10991\\Desktop\\meinv.xml");
        // 指定解析器
        SAXParseXML saxParseXML = new SAXParseXML();
        parser.parse(in, saxParseXML);
        List<MeiMei> meimeis = saxParseXML.getMeimeis();
        for (MeiMei meimei: meimeis){
            System.out.println(meimei);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒不了的星期八

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值