神刀安全网

Java之XML文件读取

XML简介

可扩展标记语言,简称XML(Extensible Markup Language),是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。如何定义这些标记,既可以选择国际通用的标记语言,比如HTML,也可以使用像XML这样由相关人士自由决定的标记语言,这就是语言的可扩展性。XML是从标准通用标记语言(SGML)中简化修改出来的。它主要用到的有可扩展标记语言、可扩展样式语言(XSL)、XBRL和XPath等。
—–维基百科

XML是一种树结构,从根部开始,扩展到枝叶。
book.xml <?xml version = "1.0" encoding = "UTF-8"?> <bookstore>     <book id = "1">         <name>Thinking in java</name>         <author>Bruce Eckel</author>         <year>2014</year>     </book>     <book id = "2" author = "liu">         <name>爱的供养</name>         <year>2004</year>     </book> </bookstore> 

第一行是XML声明,它定义XML的版本和字符编码
<bookstore>是根元素,它下面有三个子元素,</bookstore>是根元素的结尾也就是闭合标签,每个元素都必须要有相应的闭合标签,这不同于HTML。XML文档必须包含根元素,所有的元素都可以有子元素,只有你想。所有的元素可拥有文本内容和属性。同时,在XML中,标签是区分大小写的。


Java对XML文件的读取

Java对XML文件的操作一共有四种方式,分别是:

DOM
SAX
JDOM
DOM4J

其中1和2是Java官方提供的对XML操作的方式。下面我们分别来谈谈这四种解析方式。

DOM

DOM是官方提供的与平台无关的解析方式,它解析XML文件的方式是一次性把XML文件全部读取进内存,这样做的缺点就是当文件非常大时,耗内存。

优点:

1.形成了树结构,直观好理解,代码容易编写。
2.解析过程中树结构保存在内存中,方便修改。

缺点:

一次性把文件全部读取进内存,当文件大到一定程度时,耗费内存,且可能会造成内存溢出。

下面来看看DOM读取XML文件的代码

package com.codeliu.dom; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /**  * @author liu  * @version 创建时间:2018年3月24日 下午7:32:02  * 使用DOM读取XML文件的内容 DOMTest.java  */ public class DOMTest {     public static void main(String[] args) {          // 创建一个DocumentBuilderFactory对象          DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();          try {              // 创建一个DocumentBuilder对象              DocumentBuilder db = dbf.newDocumentBuilder();              // 使用parse方法解析xml文件              Document document = db.parse("book.xml");              NodeList nl = document.getElementsByTagName("book");              System.out.println("文件中包含有" + nl.getLength() + "本书");              for(int i = 0; i < nl.getLength(); i++) {                  // 通过item(i)获取一个book节点                  Node book = nl.item(i);                  // 获取一个book节点的所有属性                  NamedNodeMap nnm = book.getAttributes();                  for(int j = 0; j < nnm.getLength(); j++) {                      System.out.println(nnm.item(j).getNodeName() + ":" + nnm.item(j).getNodeValue());                 }                  NodeList childNodes = book.getChildNodes();                  // 子节点包括空格换行在内                  System.out.println("一个book节点下共有" + childNodes.getLength() + "个子节点");                  for(int m = 0; m < childNodes.getLength(); m++) {                      // 如果子节点是element类型的,就输出                      if(childNodes.item(m).getNodeType() == Node.ELEMENT_NODE) {                          System.out.println(childNodes.item(m).getNodeName() +  ":" + childNodes.item(m).getFirstChild().getNodeValue());                      }                  }              }          }          catch (ParserConfigurationException e) {              e.printStackTrace();          } catch (SAXException e) {              e.printStackTrace();          } catch (IOException e) {              e.printStackTrace();          }      } } 


SAX

SAX是官方提供的基于事件驱动的解析方式。所谓基于事件驱动的解析,就是在解析的过程中,是一步一步进行解析的,读到一个标签,就进行解析,不想DOM一样,一次性把整个文件全部读入内存。在后面的代码中我们会看到,使用SAX方式解析XML文件时,我们要写最近的Handler类继承DefaultHandler类,并重写startElement,endElement,startDocument,endDocument,以及characters方法,这样才能进行解析。

优点:

1.采用事件驱动,对内存耗费比较小。
2.适用于只需要处理XML文件中的数据,而不关心XML结构的场景。

缺点:

1.不易编码,要继承DefaultHandler类并重写方法。
2.很难同时访问同一个XML文件中不同地方的数据。

下面来看看SAX解析XML文件的代码(因为要继承,所以写了3个类)

import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; /**  * @author liu  * @version 创建时间:2018年3月24日 下午8:26:02  * 使用SAX来解析XML文件 SAXTest.java  */ public class SAXTest {      public static void main(String[] args) {          // 创建一个SAXParserFactory对象          SAXParserFactory spf = SAXParserFactory.newInstance();          try {              // 创建一个SAXParser对象              SAXParser parser = spf.newSAXParser();              // 传入自定义的handler对象              MyHandler mh = new MyHandler();              parser.parse("book.xml", mh);              for(Book book:mh.getBookList()) {              System.out.println(book);              }          } catch (ParserConfigurationException e) {              e.printStackTrace();          } catch (SAXException e) {              e.printStackTrace();          } catch (IOException e) {              e.printStackTrace();          }      } } 
/**  * @author liu  * @version 创建时间:2018年3月24日 下午9:17:38  * 读取每一本书的信息并进行保存 Book.java  */ public class Book {      private String id;      private String name;      private String author;      private String year;      /**      * @return id      */      public String getId() {          return id;      }      /**      * @param id 要设置的 id      */     public void setId(String id) {          this.id = id;      }      /**      * @return name      */      public String getName() {          return name;      }      /**      * @param name 要设置的 name       */      public void setName(String name) {          this.name = name;      }      /**      * @return author      */      public String getAuthor() {          return author;      }      /**      * @param author 要设置的 author      */      public void setAuthor(String author) {          this.author = author;      }      /**      * @return year      */      public String getYear() {          return year;      }      /**      * @param year 要设置的 year      */      public void setYear(String year) {          this.year = year;      }      @Override      public String toString() {          return "Book [id=" + id + ", name=" + name + ", author=" + author + ", year=" + year + "]";      } } 
package com.codeliu.SAX; import java.util.ArrayList; import javax.xml.stream.events.StartElement; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /**  * @author liu  * @version 创建时间:2018年3月24日 下午8:32:18  * 继承DefaultHandler类 MyHandler.java  */ public class MyHandler extends DefaultHandler {      String value = " ";      Book book = null;      private ArrayList<Book> bookList = new ArrayList<Book>();      /**      * @return bookList      */      public ArrayList<Book> getBookList() {          return bookList;      }      /**      * 用来标志解析开始      */      @Override      public void startDocument() throws SAXException {          super.startDocument();          System.out.println("start");      }      /**      * 用来标志解析结束      */     @Override      public void endDocument() throws SAXException {          super.endDocument();          System.out.println("end");      }      /**      * 用来遍历xml文件的开始标签       */      @Override      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();              System.out.println("遍历一本书开始");              int num = attributes.getLength();              for(int i = 0; i < num; i++) {                  if(attributes.getQName(i).equals("id")) {                      book.setId(attributes.getValue(i));                  } else if(attributes.getQName(i).equals("author")) {                      book.setAuthor(attributes.getValue(i));                  }              }          }       }      /**      * 获取标签中的内容      */      @Override      public void characters(char[] ch, int start, int length) throws SAXException {          super.characters(ch, start, length);          value = new String(ch, start, length);      }      /**      * 用来遍历xml文件的结束标签      */      @Override      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);          }      } } 


JDOM

JDOM不是官方提供的解析方式,所以如果我们要使用的话,得先把jar包导入,下面是下载地址http://www.jdom.org/downloads/index.html

如何在项目中导入jar包,相信大家都很熟悉,这里就不赘述,我建议大家把jar包导入的同时,把JDOM的源码一起导入,这样查看源码也方便。

1.JDOM仅使用了具体类而没有使用接口
2.JDOM的API大量使用了Collections类

下面我们来看看JDOM解析XML的方式(Book.java在上面已经贴出来了)

package com.codeliu.JDOM; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.jdom2.Attribute; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; /**  * @author liu  * @version 创建时间:2018年3月25日 上午8:34:47  * 使用JDOM解析xml文件 JDOMTest.java  */ public class JDOMTest {      public static void main(String[] args) {          SAXBuilder sb = new SAXBuilder();          // 遍历书,结果存储在books中          ArrayList<Book> books = new ArrayList<Book>();          FileInputStream in;          try {              // 创建一个输入流,将xml文件加载到输入流中              in = new FileInputStream("book.xml");              // 解析中文时出现乱码,可以改变编码格式              //InputStreamReader isr = new InputStreamReader(in, "utf-8");              // 通过build方法,将输入流加载到SAXBuilder中              Document build = sb.build(in);              // 获取根节点              Element root = build.getRootElement();              // 获取根节点下的子节点              List<Element> childList = root.getChildren();              // 获取子节点的数量              System.out.println(childList.size());              int count = 1;              for(Element child:childList) {                  Book book = new Book();                  System.out.println("--------------开始解析第" + count + "本书----------------");                 // 获取属性列表                  List<Attribute> attr = child.getAttributes();                  for(Attribute a:attr) {                      // 输出子节点的属性名和属性值                      System.out.println(a.getName() + ":" + a.getValue());                      if("id".equals(a.getName())) {                          book.setId(a.getValue());                      } else if("author".equals(a.getName())) {                          book.setAuthor(a.getValue());                      }                  }                  // 获取子节点下面的子节点                  List<Element> childrens = child.getChildren();                  for(Element children:childrens) {                      // 输出子节点的子节点的属性名和属性值                      System.out.println(children.getName() + ":" + children.getText());                      if("name".equals(children.getName())) {                          book.setName(children.getValue());                      } else if("year".equals(children.getName())) {                          book.setYear(children.getValue());                      } else if("author".equals(children.getName())) {                          book.setAuthor(children.getValue());                      }                  }                  System.out.println("------------------第" + count + "本书解析完毕----------");                  count++;                  books.add(book);                  book = null;              }              for(Book book:books) {                  System.out.println(book);              }          } catch (FileNotFoundException e) {              e.printStackTrace();          } catch (JDOMException e) {              e.printStackTrace();          } catch (IOException e) {              e.printStackTrace();          }      } } 


DOM4J

jar包下载地址https://github.com/dom4j/dom4j/releases/tag/dom4j_1_6_1

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

下面看看DOM4J解析XML文件的代码

package com.codeliu.DOM4J; import java.util.Iterator; import java.util.List; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; /**  * @author liu  * @version 创建时间:2018年3月26日 上午11:22:29  * 使用DOM4J解析xml文件  */ public class DOM4JTest {      public static void main(String[] args) {          SAXReader reader = new SAXReader();          try {              Document read = reader.read("book.xml");              // 获取根节点              Element root = read.getRootElement();              // 通过elementIterator方法获取迭代器              Iterator books = root.elementIterator();              // 遍历迭代器              while(books.hasNext()) {                  System.out.println("------------开始遍历一本书------------");                  Element b = (Element)books.next();                  // 获取每本书的属性                  List<Attribute> bookList = b.attributes();                  for(Attribute a:bookList) {                      System.out.println(a.getName() + ":" + a.getValue());                  }                  // 获取每本书下面的子节点                  Iterator childBook = b.elementIterator();                  while(childBook.hasNext()) {                      Element c = (Element)childBook.next();                      System.out.println(c.getName() + ":" + c.getStringValue());                  }                  System.out.println("-------------遍历完成一本书------------");              }          } catch (DocumentException e) {              e.printStackTrace();          }      } } 

四种解析方式的对比

我们可以把上面四种方式的解析代码整合到一个测试类里,使用System.currentTimeMillis()函数就可以对比解析同一个Book.xml各自的用时。我测试的结果如下:

DOM:461

SAX:21

JDOM:264

DOM4J:185

本文用来测试的Book.xml文件非常小,有兴趣的读者可以试试用几兆或者几十兆的xml文件进行测试,结果又会不一样。现在DOM4J使用的比较广泛,其他三种也各有各的优势,具体用什么方式,要视情况而定。

结束语

写了快两个小时,差不多又写了近1w字了,学习Java任重道远呐,一起加油吧。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Java之XML文件读取

分享到:更多 ()