四种方法解析XML文件

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book id="1">
        <name>鲁宾逊漂流记</name>
        <author>丹尼尔·笛福</author>
        <year>2014</year>
        <price>89</price>
    </book>
    <book id="2">
        <name>老人与海</name>
        <year>2004</year>
        <price>77</price>
        <language>English</language>
    </book>
</bookstore>

例如对该XML文件进行解析

1. DOM

  • DOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准
  • 不仅能读,还能修改,而且能够实现随机访问,缺点是解析速度慢,适合解析小型文档
  • 一般应用于小型的配置XML,方便操作
  • 为载入到内存的文档节点建立类型描述,呈现可横向移动、潜在巨大的树型结构
  • 当xml文件较大时,对内存消耗比较大,容易影响解析性能并造成内存溢出

准备工作:
1..创建一个DocumentBuilderFactory对象

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

2..创建一个DocumentBuilder对象

DocumentBuilder db = dbf.newDocumentBuilder();

3..通过DocumentBuilder的parse方法加载book.xml文件到当前项目下

Document document = db.parse("book.xml");

开始解析:
1..获取到所有的book节点

NodeList bookList = document.getElementsByTagName("book");

2..通过bookList.getLength()可以获取到book节点的个数,通过bookList.item(index)可以对指定的book节点进行操作,从而遍历每个book节点的子节点

Node book = bookList.item(i);  //省略for循环

3..获取book节点的所有属性集合(这里book只有 id 这一个属性)

NamedNodeMap attrs = book.getAttributes();

4..遍历book的属性

for (int j = 0; j < attrs.getLength(); j++) {
    //通过item(index)方法获取book节点的某一个属性
    Node attr = attrs.item(j);
    //获取属性名
    System.out.println("属性名:" + attr.getNodeName());
    //获取属性值
    System.out.println("属性值" + attr.getNodeValue());
}

也可以直接通过’id’获取到其值

String attrValue = book.getAttribute("id");

5..解析book节点的子节点,获取子节点列表

NodeList childNodes = book.getChildNodes();

6..遍历子节点列表,获取节点名和节点值

for (int k = 0; k < childNodes.getLength(); k++) {
    //区分出text类型的node以及element类型的node
    if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {
        //获取element类型节点的节点名
        System.out.print("第" + (k + 1) + "个节点的节点名:" + childNodes.item(k).getNodeName());
        //获取element类型节点的节点值
        System.out.println("--节点值是:" +childNodes.item(k).getFirstChild().getNodeValue());
        //也可以通过getTextContent()获取节点值
        //System.out.println("--节点值是:" + childNodes.item(k).getTextContent());
    }
}

对于该XML文件来说
这里写图片描述
每对标签都是一个节点,id是属性,每个换行是一个text,所以book的子节点列表的长度为9

2. SAX

  • 只能读,不能修改,只能顺序访问,适合解析大型XML,解析速度快
  • 采用事件驱动模式,对内存消耗比较小
  • 常应用于处理大量数据的XML,实现异构系统的数据访问,实现跨平台
  • 从文档的开始通过每一节点移动,定位一个特定的节点
  • 适用于只需要处理xml中数据时

SAXTest.java

public class SAXTest {

    public static void main(String[] args) {
        //获取SAXParserFactory的实例
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            //通过factory获取SAXParser实例
            SAXParser parser = factory.newSAXParser();
            //加载book.xml文件到当前项目下
            parser.parse("books.xml", new SAXParseHandle());
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

parse方法第二个参数是一个handle对象实例,这里需要创建一个类,该类继承DefaultHandler类,并通过重写该类的方法来定义解析规则

SAXParseHandle.java

public class SAXParseHandle extends DefaultHandler {

    ArrayList<Book> bookList = new ArrayList<Book>();
    Book book = null;
    String value = null;
    //用来标识解析开始
    public void startDocument() throws SAXException {
        super.startDocument();
        System.out.println("sax解析开始.......");
    }
    //用来标识解析结束
    public void endDocument() throws SAXException {
        super.endDocument();
        System.out.println("sax解析结束.......");
    }
    //用来遍历XML文件的开始标签
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        if(qName.equals("book"))
        {   
            book = new Book();
            //已知book属性名的情况下
            //System.out.println("id="+attributes.getValue("id"));
            //不知道book属性名的情况下
            for(int i = 0;i < attributes.getLength();i++) {
                System.out.println(attributes.getQName(i)+"--"+attributes.getValue(attributes.getQName(i)));
                if (attributes.getQName(i).equals("id")) {
                    book.setId(attributes.getValue(i));
                }
            }
        }else if(!qName.equals("bookstore")&&!qName.equals("book")) {
            System.out.print(qName+"--");
        }
    }
    //用来遍历XML文件的结束标签
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        if (qName.equals("book")) {
            bookList.add(book);
            book = null;
            System.out.println("======================结束遍历某一本书的内容=================");
        }
        else if (qName.equals("name")) {
            book.setName(value);
        }
        else if (qName.equals("author")) {
            book.setAuthor(value);
        }
        else if (qName.equals("year")) {
            book.setYear(value);
        }
        else if (qName.equals("price")) {
            book.setPrice(Integer.parseInt(value));
        }
        else if (qName.equals("language")) {
            book.setLanguage(value);
        }
    }
    //用来获取标签间的文本
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        value = new String(ch,start,length);
        if(!value.trim().equals(""))   //去掉空格后不为空
            System.out.println(value);
    }
    public ArrayList<Book> getBookList(){
        return bookList;
    }
}

如果要创建一个book实体类来保存读取到的XML文件内容,可以在endElement方法里判断标签内容,进而将characters方法里的valueset到book的相应属性中。这里也可以看出从节点头到节点内容再到节点尾,分别就对应着startElement,characters,endElement三个方法。

3. JDOM

  • 仅使用具体类而不使用接口,灵活性低
  • API大量使用了Collections类

先要导入JDOM的jar包

public class JDOMTest {

    public static void main(String[] args) {
        //创建一个SAXBuilder对象
        SAXBuilder saxbuilder = new SAXBuilder();
        try {
            //将XML文件加载到输入流中,进而加载到SAXBuilder中
            Document document = saxbuilder.build(new FileInputStream("books.xml"));
            //获取XML文件的根节点
            Element rootElement = document.getRootElement();
            //获取根节点下的子节点的集合
            List<Element> booklist= rootElement.getChildren();
            for (Element book : booklist) {
                //遍历每个book的属性
                //若已经知道属性名,可通过book.getAttribute("id").getValue()获取
                List<Attribute> bookAttrs = book.getAttributes();
                for (Attribute attribute : bookAttrs) {
                    System.out.println(attribute.getName()+"--"+attribute.getValue());
                }
                //遍历每个book的子节点
                List<Element> bookChildren = book.getChildren();
                for (Element element : bookChildren) {
                    System.out.println(element.getName()+"--"+element.getValue());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4. DOM4J

  • JDOM的一种智能分支,它合并了许多超出基本XML文档表示的功能
  • DOM4J使用接口和抽象基本类方法,是一个优秀的Java XML API
  • 具有性能优异、灵活性好、功能强大和极端易使用的特点

先要导入DOM4J的jar包

public class DOM4JTest {

    public static void main(String[] args) {
        // 创建SAXReader的对象reader
        SAXReader reader = new SAXReader();
        try {
            //加载books.xml文件
            Document document = reader.read(new File("books.xml"));
            //获取根节点
            Element bookstore = document.getRootElement();
            //获取迭代器
            Iterator it = bookstore.elementIterator();
            //迭代遍历
            while(it.hasNext())
            {
                Element book = (Element) it.next();
                //获取book的属性名以及属性值
                List<Attribute> bookAttrs = book.attributes();
                for (Attribute attr : bookAttrs) {
                    System.out.println(attr.getName()+"--"+attr.getValue());
                }
                //获取book的子节点及节点的值
                Iterator it2 = book.elementIterator();
                while(it2.hasNext())
                {
                    Element bookChild = (Element) it2.next();
                    System.out.println(bookChild.getName()+"--"+bookChild.getStringValue());
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值