Java 解析XML文件

XML是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性、给数据集成与交互带来了极大的方便。XML在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。

XML解析——Java中XML的四种解析方式

XML的解析方式分为四种:1、DOM解析;2、SAX解析;3、JDOM解析;4、DOM4J解析。其中前两种属于基础方法,是官方提供的平台无关的解析方式;后两种属于扩展方法,它们是在基础的方法上扩展出来的,只适用于java平台。

  • DOM方式解析XML

Dom解析是将xml文件全部载入到内存,组装成一颗dom树,然后通过节点以及节点之间的关系来解析xml文件,与平台无关,java提供的一种基础的解析XML文件的API,理解较简单,但是由于整个文档都需要载入内存,不适用于文档较大时。

  • SAX方式解析XML

基于事件驱动,逐条解析,适用于只处理xml数据,不易编码,而且很难同时访问同一个文档中的多处不同数据

  • JDOM方式解析XML

简化与XML的交互并且比使用DOM实现更快,仅使用具体类而不使用接口因此简化了API,并且易于使用

  • DOM4j方式解析XML

JDOM的一种智能分支,功能较强大,建议熟练使用

针对以下XML文件,会对四种方式进行详细描述:
books.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>  
        <author>安徒生</author>  
        <year>2004</year>  
        <price>77</price>  
    </book>  
    <book id=“3”>  
        <name>think think think</name>  
        <author>aaa</author>  
        <year>1997</year>  
        <price>100</price>  
    </book>  
</bookstore>  

bean类:Book.java:

public class Book {  

    /** 
     */  

    private int id;  
    private String name;  
    private String author;  
    private int year;  
    private double price;  

    /** 
     * @return the id 
     */  
    public int getId() {  
        return id;  
    }  
    /** 
     * @param id the id to set 
     */  
    public void setId(int id) {  
        this.id = id;  
    }  
    /** 
     * @return the name 
     */  
    public String getName() {  
        return name;  
    }  
    /** 
     * @param name the name to set 
     */  
    public void setName(String name) {  
        this.name = name;  
    }  
    /** 
     * @return the author 
     */  
    public String getAuthor() {  
        return author;  
    }  
    /** 
     * @param author the author to set 
     */  
    public void setAuthor(String author) {  
        this.author = author;  
    }  
    /** 
     * @return the year 
     */  
    public int getYear() {  
        return year;  
    }  
    /** 
     * @param year the year to set 
     */  
    public void setYear(int year) {  
        this.year = year;  
    }  
    /** 
     * @return the price 
     */  
    public double getPrice() {  
        return price;  
    }  
    /** 
     * @param price the price to set 
     */  
    public void setPrice(double price) {  
        this.price = price;  
    }  

    @Override  
    public String toString() {  
        return “Book [id=” + id + “, name=” + name + “, author=” + author + “, year=” + year + “, price=” + price + “]”;  
    }  

}  

一、DOM解析

  DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。

  DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,这些分层对象模型依据XML的文档结构形成了一棵节点树。无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用DOM所生成的模型都是节点树的形式。也就是说,DOM强制使用树模型来访问XML文档中的信息。由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。

  DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,DOM分析器还是有很广泛的使用价值的。

优点:

1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。
2、解析过程中,树结构保存在内存中,方便修改。

缺点:

1、由于文件是一次性读取,所以对内存的耗费比较大。
2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。

以下是解析代码:

/** 
 * 用DOM方式读取xml文件 
 */  
public class ReadxmlByDom {  
    private static DocumentBuilderFactory dbFactory = null;  
    private static DocumentBuilder db = null;  
    private static Document document = null;  
    private static List<Book> books = null;  
    static{  
        try {  
            dbFactory = DocumentBuilderFactory.newInstance();  
            db = dbFactory.newDocumentBuilder();  
        } catch (ParserConfigurationException e) {  
            e.printStackTrace();  
        }  
    }  

    public static List<Book> getBooks(String fileName) throws Exception{  
        //将给定 URI 的内容解析为一个 XML 文档,并返回Document对象  
        document = db.parse(fileName);  
        //按文档顺序返回包含在文档中且具有给定标记名称的所有 Element 的 NodeList  
        NodeList bookList = document.getElementsByTagName(”book”);  
        books = new ArrayList<Book>();  
        //遍历books  
        for(int i=0;i<bookList.getLength();i++){  
            Book book = new Book();  
            //获取第i个book结点  
            org.w3c.dom.Node node = bookList.item(i);  
            //获取第i个book的所有属性  
            NamedNodeMap namedNodeMap = node.getAttributes();  
            //获取已知名为id的属性值  
            String id = namedNodeMap.getNamedItem(”id”).getTextContent();//System.out.println(id);  
            book.setId(Integer.parseInt(id));  

            //获取book结点的子节点,包含了Test类型的换行  
            NodeList cList = node.getChildNodes();//System.out.println(cList.getLength());9  

            //将一个book里面的属性加入数组  
            ArrayList<String> contents = new ArrayList<>();  
            for(int j=1;j<cList.getLength();j+=2){  

                org.w3c.dom.Node cNode = cList.item(j);  
                String content = cNode.getFirstChild().getTextContent();  
                contents.add(content);  
                //System.out.println(contents);  
            }  

            book.setName(contents.get(0));  
            book.setAuthor(contents.get(1));  
            book.setYear(Integer.parseInt(contents.get(2)));  
            book.setPrice(Double.parseDouble(contents.get(3)));  
            books.add(book);  
        }  

        return books;  

    }  

    public static void main(String args[]){  
        String fileName = ”src/res/books.xml”;  
        try {  
            List<Book> list = ReadxmlByDom.getBooks(fileName);  
            for(Book book :list){  
                System.out.println(book);  
            }  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  

}  

二、SAX解析

  SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。

优点:

1、采用事件驱动模式,对内存耗费比较小。
2、适用于只处理XML文件中的数据时。

缺点:

1、编码比较麻烦。
2、很难同时访问XML文件中的多处不同数据。

以下是解析代码:

/** 
 * 用SAX解析xml文件时需要的handler 
 */  
public class SAXParseHandler extends DefaultHandler {  
    private List<Book> list;         //存放解析到的book数组  
    private Book book;               //存放当前解析的book  

    private String content = null;   //存放当前节点值  

    /** 
     * 开始解析xml文档时调用此方法 
     */  
    @Override  
    public void startDocument() throws SAXException {  

        super.startDocument();  
        System.out.println(”开始解析xml文件”);  
        list = new ArrayList<Book>();  
    }  



    /**  
     * 文档解析完成后调用此方法 
     */  
    @Override  
    public void endDocument() throws SAXException {  

        super.endDocument();  
        System.out.println(”xml文件解析完毕”);  
    }  



    /** 
     * 开始解析节点时调用此方法 
     */  
    @Override  
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {  

        super.startElement(uri, localName, qName, attributes);  

        //当节点名为book时,获取book的属性id  
        if(qName.equals(“book”)){  
            book = new Book();  
            String id = attributes.getValue(”id”);//System.out.println(“id值为”+id);  
            book.setId(Integer.parseInt(id));  
        }  

    }  


    /** 
     *节点解析完毕时调用此方法 
     * 
     *@param qName 节点名 
     */  
    @Override  
    public void endElement(String uri, String localName, String qName) throws SAXException {  

        super.endElement(uri, localName, qName);  
        if(qName.equals(“name”)){  
            book.setName(content);  
            //System.out.println(“书名”+content);  
        }else if(qName.equals(“author”)){  
            book.setAuthor(content);  
        //  System.out.println(“作者”+content);  
        }else if(qName.equals(“year”)){  
            book.setYear(Integer.parseInt(content));  
        //  System.out.println(“年份”+content);  
        }else if(qName.equals(“price”)){  
            book.setPrice(Double.parseDouble(content));  
        //  System.out.println(“价格”+content);  
        }else if(qName.equals(“book”)){         //当结束当前book解析时,将该book添加到数组后置为空,方便下一次book赋值  
            list.add(book);  
            book = null;  
        }     

    }  



    /**  
     * 此方法用来获取节点的值 
     */  
    @Override  
    public void characters(char[] ch, int start, int length) throws SAXException {  

        super.characters(ch, start, length);  

        content = new String(ch, start, length);  
        //收集不为空白的节点值  
//      if(!content.trim().equals(“”)){  
//          System.out.println(“节点值为:”+content);  
//      }  

    }  

    public List<Book> getBooks(){  
        return list;  
    }  

}  
/** 
 * 用SAX方式读取xml文件 
 */  
public class ReadXmlBySAX {  

    private static List<Book> books = null;  

    private  SAXParserFactory sParserFactory = null;  
    private  SAXParser parser = null;  


    public List<Book> getBooks(String fileName) throws Exception{  
        SAXParserFactory sParserFactory = SAXParserFactory.newInstance();  
        SAXParser parser = sParserFactory.newSAXParser();  

        SAXParseHandler handler = new SAXParseHandler();  
        parser.parse(fileName, handler);  

        return handler.getBooks();  

    }  
    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
        try {  
            books = new ReadXmlBySAX().getBooks(“src/res/books.xml”);  
            for(Book book:books){  
                System.out.println(book);  
            }  

        } catch (Exception e) {  
            e.printStackTrace();  
        }  

    }  

}  

三、JDOM解析

特征:

1、仅使用具体类,而不使用接口。
2、API大量使用了Collections类。

以下是解析代码:

/** 
 * 用JDOM方式读取xml文件 
 */  
public class ReadXMLByJDom {  

    private List<Book> books = null;  
    private Book book = null;  

    public List<Book> getBooks(String fileName){  
        SAXBuilder saxBuilder = new SAXBuilder();  
        try {  
            Document document = saxBuilder.build(new FileInputStream(fileName));  
            //获取根节点bookstore  
            Element rootElement = document.getRootElement();  
            //获取根节点的子节点,返回子节点的数组  
            List<Element> bookList = rootElement.getChildren();  
            books = new ArrayList<Book>();  
            for(Element bookElement : bookList){  
                book = new Book();  
                //获取bookElement的属性  
                List<Attribute> bookAttributes = bookElement.getAttributes();  
                for(Attribute attribute : bookAttributes){  
                    if(attribute.getName().equals(“id”)){  
                        String id = attribute.getValue(); //System.out.println(id);  
                        book.setId(Integer.parseInt(id));  
                    }  
                }  
                //获取bookElement的子节点  
                List<Element> children = bookElement.getChildren();  
                for(Element child : children){  
                    if(child.getName().equals(“name”)){  
                        String name = child.getValue();//System.out.println(name);  
                        book.setName(name);  
                    }else if(child.getName().equals(“author”)){  
                        String author = child.getValue();  
                        book.setAuthor(author);//System.out.println(author);  
                    }else if(child.getName().equals(“year”)){  
                        String year = child.getValue();  
                        book.setYear(Integer.parseInt(year));  
                    }else if(child.getName().equals(“price”)){  
                        String price = child.getValue();  
                        book.setPrice(Double.parseDouble(price));  
                    }  

                }  

                books.add(book);  
                book = null;  

            }  

        } catch (FileNotFoundException e) {  

            e.printStackTrace();  
        } catch (JDOMException e) {  

            e.printStackTrace();  
        } catch (IOException e) {  

            e.printStackTrace();  
        }  

        return books;  

    }  


    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        String fileName = ”src/res/books.xml”;  
        List<Book> books= new ReadXMLByJDom().getBooks(fileName);  
        for(Book book : books){  
            System.out.println(book);  
        }  
    }  

}  

4、DOM4J解析

特征:

1、JDOM的一种智能分支,它合并了许多超出基本XML文档表示的功能。
2、它使用接口和抽象基本类方法。
3、具有性能优异、灵活性好、功能强大和极端易用的特点。
4、是一个开放源码的文件

以下是解析代码:

/** 
 * 用DOM4J方法读取xml文件 
 */  
public class ReadXMLByDom4j {  

    private List<Book> bookList = null;  
    private Book book = null;  

    public List<Book> getBooks(File file){  

        SAXReader reader = new SAXReader();  
        try {  
            Document document = reader.read(file);  
            Element bookstore = document.getRootElement();  
            Iterator storeit = bookstore.elementIterator();  

            bookList = new ArrayList<Book>();  
            while(storeit.hasNext()){  

                book = new Book();  
                Element bookElement = (Element) storeit.next();  
                //遍历bookElement的属性  
                List<Attribute> attributes = bookElement.attributes();  
                for(Attribute attribute : attributes){  
                    if(attribute.getName().equals(“id”)){  
                        String id = attribute.getValue();//System.out.println(id);  
                        book.setId(Integer.parseInt(id));  
                    }  
                }  

                Iterator bookit = bookElement.elementIterator();  
                while(bookit.hasNext()){  
                    Element child = (Element) bookit.next();  
                    String nodeName = child.getName();  
                    if(nodeName.equals(“name”)){  
                        //System.out.println(child.getStringValue());  
                        String name = child.getStringValue();  
                        book.setName(name);  
                    }else if(nodeName.equals(“author”)){  
                        String author = child.getStringValue();  
                        book.setAuthor(author);  
                    }else if(nodeName.equals(“year”)){  
                        String year = child.getStringValue();  
                        book.setYear(Integer.parseInt(year));  
                    }else if(nodeName.equals(“price”)){  
                        String price = child.getStringValue();  
                        book.setPrice(Double.parseDouble(price));  
                    }  
                }  
                bookList.add(book);  
                book = null;  

            }  
        } catch (DocumentException e) {  

            e.printStackTrace();  
        }  


        return bookList;  

    }  


    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        File file = new File(“src/res/books.xml”);  
        List<Book> bookList = new ReadXMLByDom4j().getBooks(file);  
        for(Book book : bookList){  
            System.out.println(book);  
        }  
    }  

}  

Final:比较总结

  DOM4J性能最好,连Sun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J。
  JDOM和DOM在性能测试时表现不佳,在测试10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM。虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础,因为它正式获得W3C推荐(与基于非标准的Java模型相对),所以在某些类型的项目中可能也需要它(如在JavaScript中使用DOM)。
  SAX表现较好,这要依赖于它特定的解析方式-事件驱动。一个SAX检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值