你的位置:首页 > Java教程

[Java教程]Java文件操作①——XML文件的读取


一、邂逅

文件种类是丰富多彩的,

   存储结构:树形结构;

 

节点名称区分大小写。

1、<book id="1"></book> id为属性, <book><id>1</id></book> id为节点
2、

 比如:

❤ 为什么要使用

思考1:不同应用程序之间的通信?

思考2:不同平台间的通信?

思考3:不同平台间的数据共享?

答案就是我们要学习的

二、应用 DOM 方式解析

❤ 在Java程序中如何获取

解析的目的:获取节点名、节点值、属性名、属性值;

四种解析方式:DOM、SAX、DOM4J、JDOM 

DOM、SAX :java 官方方式,不需要下载jar包
DOM4J、JDOM :第三方,需要网上下载jar包

示例:解析

思考:如何在Java程序中保留

 

如何保留节点之间的层级关系?

注意常用的节点类型:

 下面介绍DOM方式解析

 功能说明:

代码示例:

 1 package com.study.domtest; 2  3 import java.io.IOException; 4  5 import javax. 6 import javax. 7 import javax. 8  9 import org.w3c.dom.Document;10 import org.w3c.dom.NamedNodeMap;11 import org.w3c.dom.Node;12 import org.w3c.dom.NodeList;13 import org.14 15 /**16  * DOM方式解析17 */18 public class DOMTest {19 20   public static void main(String[] args) {21     //1、创建一个DocumentBuilderFactory的对象22     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();23     //2、创建一个DocumentBuilder的对象24     try {25       //创建DocumentBuilder对象26       DocumentBuilder db = dbf.newDocumentBuilder();27       //3、通过DocumentBuilder对象的parser方法加载books.28       /*注意导入Document对象时,要导入org.w3c.dom.Document包下的*/29       Document document = db.parse("books.//传入文件名可以是相对路径也可以是绝对路径30       //获取所有book节点的集合31       NodeList bookList = document.getElementsByTagName("book");32       //通过nodelist的getLength()方法可以获取bookList的长度33       System.out.println("一共有" + bookList.getLength() + "本书");34       //遍历每一个book节点35       for (int i = 0; i < bookList.getLength(); i++) {36         System.out.println("=================下面开始遍历第" + (i + 1) + "本书的内容=================");37     //❤未知节点属性的个数和属性名时:38         //通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始39         Node book = bookList.item(i);40         //获取book节点的所有属性集合41         NamedNodeMap attrs = book.getAttributes();42         System.out.println("第 " + (i + 1) + "本书共有" + attrs.getLength() + "个属性");43         //遍历book的属性44         for (int j = 0; j < attrs.getLength(); j++) {45           //通过item(index)方法获取book节点的某一个属性46           Node attr = attrs.item(j);47           //获取属性名48           System.out.print("属性名:" + attr.getNodeName());49           //获取属性值50           System.out.println("--属性值" + attr.getNodeValue());51         }52      //❤已知book节点有且只有1个id属性:53       /* 54        //前提:已经知道book节点有且只能有1个id属性55        //将book节点进行强制类型转换,转换成Element类型56        Element book1 = (Element) bookList.item(i);57        //通过getAttribute("id")方法获取属性值58        String attrValue = book1.getAttribute("id");59        System.out.println("id属性的属性值为" + attrValue);60        */61         62       //解析book节点的子节点63         NodeList childNodes = book.getChildNodes();64        //遍历childNodes获取每个节点的节点名和节点值65         System.out.println("第" + (i+1) + "本书共有" + childNodes.getLength() + "个子节点");66         for (int k = 0; k < childNodes.getLength(); k++) {67          //区分出text类型的node以及element类型的node68           if(childNodes.item(k).getNodeType() == Node.ELEMENT_NODE){69            //获取了element类型节点的节点名70             System.out.print("第" + (k + 1) + "个节点的节点名:" + childNodes.item(k).getNodeName());71            //获取了element类型节点的节点值72             System.out.println("--节点值是:" + childNodes.item(k).getFirstChild().getNodeValue());73 //            System.out.println("--节点值是:" + childNodes.item(k).getTextContent());74           }75         }76         System.out.println("======================结束遍历第" + (i + 1) + "本书的内容=================");77       }78 79     } catch (ParserConfigurationException e) {80       e.printStackTrace();81     } catch (SAXException e) {82       e.printStackTrace();83     } catch (IOException e) {84       e.printStackTrace();85     }86   }87 88 }

 三、应用 SAX 方式解析

SAX是SIMPLE API FOR

Dom解析会将整个
Sax解析是通过Handler处理类逐个依次解析每个节点

在处理DOM的时候,我们需要读入整个的

❤ 

代码示例:Book实体类

 1 package com.study.saxtest.entity; 2  3 /** 4  * 用Book实体类代表 5  * 在遇到<book>标签,证明我们要存储新的book时需要创建Book对象 6 */ 7 public class Book { 8   private String id; 9   private String name;10   private String author;11   private String year;12   private String price;13   private String language;14   public String getId() {15   return id;16   }17   public void setId(String id) {18   this.id = id;19   }20   public String getName() {21   return name;22   }23   public void setName(String name) {24   this.name = name;25   }26   public String getAuthor() {27   return author;28   }29   public void setAuthor(String author) {30   this.author = author;31   }32   public String getYear() {33   return year;34   }35   public void setYear(String year) {36   this.year = year;37   }38   public String getPrice() {39   return price;40   }41   public void setPrice(String price) {42   this.price = price;43   }44   public String getLanguage() {45   return language;46   }47   public void setLanguage(String language) {48   this.language = language;49   }50 }

SAXParserHandler类:

 1 package com.study.saxtest.handler; 2  3 import java.util.ArrayList; 4  5 import org. 6 import org. 7 import org. 8  9 import com.study.saxtest.entity.Book; 10  11 public class SAXParserHandler extends DefaultHandler{ 12   /*注意DefaultHandler是org.*/ 13    14   int bookIndex = 0;//设置全局变量,用来记录是第几本书 15    16   String value = null; 17   Book book = null; 18   private ArrayList<Book> bookList = new ArrayList<Book>();//保存book对象 19  20   public ArrayList<Book> getBookList() { 21     return bookList; 22   } 23  24   /** 25    * 用来标识解析开始 26   */ 27   @Override 28   public void startDocument() throws SAXException { 29     super.startDocument(); 30     System.out.println("SAX解析开始"); 31  32   } 33    34   /** 35    * 用来标识解析结束 36   */ 37   @Override 38   public void endDocument() throws SAXException { 39     super.endDocument(); 40     System.out.println("SAX解析结束"); 41   } 42    43   /** 44    * 用来遍历 45    * 解析 46   */ 47   @Override 48   public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException { 49     //调用DefaultHandler类的startElement方法 50     super.startElement(uri, localName, qName, attributes); 51     if (qName.equals("book")) { 52       bookIndex++; 53       //创建一个book对象 54       /*Book*/ book = new Book(); 55       //开始解析book元素的属性 56       System.out.println("======================开始遍历第"+bookIndex+"本书的内容================="); 57      /* //❤已知节点的属性名时:比如已知id属性,根据属性名称获取属性值 58       String value = attributes.getValue("id"); 59       System.out.print("book的属性值是:"+value);*/ 60      //❤未知节点的属性名时,获取属性名和属性值 61       int num=attributes.getLength(); 62       for(int i=0;i<num;i++){ 63         System.out.print("book元素的第"+(i+1)+"个属性名是:"+attributes.getQName(i)); 64         System.out.println("---属性值是:"+attributes.getValue(i)); 65         if (attributes.getQName(i).equals("id")) {//往book对象中塞值 66           book.setId(attributes.getValue(i)); 67         } 68       } 69     }else if (!qName.equals("book") && !qName.equals("bookstore")) { 70       System.out.print("节点名是:" + qName + "---");//此时qName获取的是节点名(标签) 71     } 72   } 73    74   /** 75    * 用来遍历 76   */ 77   @Override 78   public void endElement(String uri, String localName, String qName) throws SAXException { 79     //调用DefaultHandler类的endElement方法 80     super.endElement(uri, localName, qName); 81     //判断是否针对一本书已经遍历结束 82     if (qName.equals("book")) { 83       bookList.add(book);//在清空book对象之前先保存 84       book = null;//把book清空,方便解析下一个book节点 85       System.out.println("======================结束遍历第"+bookIndex+"本书的内容================="); 86     }else if (qName.equals("name")) { 87       book.setName(value); 88     } 89     else if (qName.equals("author")) { 90      book.setAuthor(value); 91     } 92     else if (qName.equals("year")) { 93      book.setYear(value); 94     } 95     else if (qName.equals("price")) { 96      book.setPrice(value); 97     } 98     else if (qName.equals("language")) { 99      book.setLanguage(value);100     }101   }102   103   /**104    * 获取文本105    * 重写charaters()方法时,106    * String(byte[] bytes,int offset,int length)的构造方法进行数组的传递107    * 去除解析时多余空格108   */109   @Override110   public void characters(char[] ch, int start, int length)throws SAXException {111     /**112      * ch 代表节点中的所有内容,即每次遇到一个标签调用characters方法时,数组ch实际都是整个113      * 如何每次去调用characters方法时我们都可以获取不同的节点属性?这时就必须结合start(开始节点)和length(长度)114     */115     super.characters(ch, start, length);116     /*String */value = new String(ch, start, length);//value获取的是文本(开始和结束标签之间的文本)117 //    System.out.println(value);//输出时会多出两个空格,是因为118     if(!value.trim().equals("")){//如果value去掉空格后不是空字符串119       System.out.println("节点值是:" + value);120     }121   }122   123   /**124    * qName获取的是节点名(标签)125    * value获取的是文本(开始和结束标签之间的文本)126    * 思考:qName和value分别在两个方法中,如何将这两个方法中的参数整合到一起?127    * 分析:要在两个方法中用同一个变量,就设置成全局变量,可以赋初值为null。128    *   可以把characters()方法中的value作成一个全局变量129    * 130    * 然后在endElement()方法中对book对象进行塞值。记得要把Book对象设置为全局变量,变量共享131   */132 }

测试类:SAXTest

 1 package com.study.saxtest.test; 2  3 import java.io.IOException; 4  5 import javax. 6 import javax. 7 import javax. 8  9 import org.10 11 import com.study.saxtest.entity.Book;12 import com.study.saxtest.handler.SAXParserHandler;13 14 /**15  * sax方式解析16 */17 public class SAXTest {18 19   public static void main(String[] args) {20     //1.获取一个SAXParserFactory的实例对象21     SAXParserFactory factory = SAXParserFactory.newInstance();22     //2.通过factory的newSAXParser()方法获取一个SAXParser类的对象。23     try {24       SAXParser parser = factory.newSAXParser();25       //创建SAXParserHandler对象26       SAXParserHandler handler = new SAXParserHandler();27       parser.parse("books., handler);28       System.out.println("~~~~~共有"+handler.getBookList().size()+"本书");29       for (Book book : handler.getBookList()) {30         System.out.println(book.getId());31         System.out.println(book.getName());32         System.out.println(book.getAuthor());33         System.out.println(book.getYear());34         System.out.println(book.getPrice());35         System.out.println(book.getLanguage());36         System.out.println("----finish----");37       }38     } catch (ParserConfigurationException e) {39       e.printStackTrace();40     } catch (SAXException e) {41       e.printStackTrace();42     } catch (IOException e) {43       e.printStackTrace();44     }45   }46 47 }

 运行结果:

SAX解析开始======================开始遍历第1本书的内容=================book元素的第1个属性名是:id---属性值是:1节点名是:name---节点值是:冰与火之歌节点名是:author---节点值是:乔治马丁节点名是:year---节点值是:2014节点名是:price---节点值是:89======================结束遍历第1本书的内容=======================================开始遍历第2本书的内容=================book元素的第1个属性名是:id---属性值是:2节点名是:name---节点值是:安徒生童话节点名是:year---节点值是:2004节点名是:price---节点值是:77节点名是:language---节点值是:English======================结束遍历第2本书的内容=================SAX解析结束~~~~~共有2本书1冰与火之歌乔治马丁201489null----finish----2安徒生童话null200477English----finish----

View Code

 四、应用 DOM4J 及 JDOM 方式解析

 # JDOM 方式解析

  JDOM 开始解析前的准备工作:

  JDOM是第三方提供的解析

 

 示例代码:

 1 package com.study.jdomtest1.test; 2  3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.InputStreamReader; 8 import java.util.ArrayList; 9 import java.util.List; 10  11 import org.jdom2.Attribute; 12 import org.jdom2.Document; 13 import org.jdom2.Element; 14 import org.jdom2.JDOMException; 15 import org.jdom2.input.SAXBuilder; 16  17 import com.study.jdomtest1.entity.Book; 18  19 /** 20  * JDOM 解析 21 */ 22 public class JDOMTest { 23   private static ArrayList<Book> booksList = new ArrayList<Book>(); 24  25   public static void main(String[] args) { 26     // 进行对books. 27     //❤准备工作 28     // 1.创建一个SAXBuilder的对象 29     SAXBuilder saxBuilder = new SAXBuilder();//注意SAXBuilder是org.jdom2.input包下的 30     InputStream in; 31     try { 32       // 2.创建一个输入流,将 33       in=new FileInputStream("books.//如果将 34       InputStreamReader isr = new InputStreamReader(in, "UTF-8");//使用包装流InputStreamReader进行读取编码的指定,防止乱码 35       // 3.通过saxBuilder的build方法,将输入流加载到saxBuilder中 36       Document document = saxBuilder.build(isr); 37       // 4.通过document对象获取 38       Element rootElement = document.getRootElement(); 39       // 5.获取根节点下的子节点的List集合 40       List<Element> bookList = rootElement.getChildren(); 41       //❤ 继续解析,采用for循环对bookList进行遍历 42       for (Element book : bookList) { 43         Book bookEntity = new Book(); 44         System.out.println("======开始解析第" + (bookList.indexOf(book) + 1) + "书======");//indexOf()返回的是index的位置,是从0开始 45         // 解析book的属性集合 46         List<Attribute> attrList = book.getAttributes();//适用于未知属性情况下 47         /*//知道节点下属性名称时,获取节点值 48         book.getAttributeValue("id");*/ 49         // 遍历attrList(针对不清楚book节点下属性的名字及数量) 50         for (Attribute attr : attrList) { 51           /**注:JDom中,Attribute的getName和getValue方法获取到的都是实际的名称和值, 52            * 不会出现SAX和DOM中的空格和换行的情况*/ 53           // 获取属性名 54           String attrName = attr.getName(); 55           // 获取属性值 56           String attrValue = attr.getValue(); 57           System.out.println("属性名:" + attrName + "----属性值:" + attrValue); 58           if (attrName.equals("id")) { 59             bookEntity.setId(attrValue); 60             } 61         } 62          63         //❤对book节点的子节点的节点名以及节点值的遍历 64         List<Element> bookChilds = book.getChildren(); 65         for (Element child : bookChilds) { 66           System.out.println("节点名:" + child.getName() + "----节点值:" + child.getValue()); 67           if (child.getName().equals("name")) { 68             bookEntity.setName(child.getValue()); 69             } 70            else if (child.getName().equals("author")) { 71             bookEntity.setAuthor(child.getValue()); 72             } 73            else if (child.getName().equals("year")) { 74             bookEntity.setYear(child.getValue()); 75             } 76            else if (child.getName().equals("price")) { 77             bookEntity.setPrice(child.getValue()); 78             } 79            else if (child.getName().equals("language")) { 80             bookEntity.setLanguage(child.getValue()); 81             } 82  83         } 84         System.out.println("======结束解析第" + (bookList.indexOf(book) + 1) + "书======"); 85         booksList.add(bookEntity); 86         bookEntity = null; 87         //测试数据 88         System.out.println(booksList.size()); 89         System.out.println(booksList.get(0).getId()); 90         System.out.println(booksList.get(0).getName()); 91  92       } 93     } catch (FileNotFoundException e) { 94       e.printStackTrace(); 95     } catch (JDOMException e) { 96       e.printStackTrace(); 97     } catch (IOException e) { 98       e.printStackTrace(); 99     }100   }101 102 }

注意:

❤关于 JDOM 使用过程中 JAR 包的引用 :

方式1:通过右击项目-->build path-->add external archives...-->然后选择本地文件的jar包
这种方式并不能将jar包真正导入到项目源码中,当把项目导出放在另外的机器上,这个jar包并不会随着project一同被导出。

如图:

方式2:项目根目录下新建lib文件夹——复制、粘帖jar包——右击jar包选择“build path构建路径”——“add to build path添加至构建路径”即可

如图:

  # DOM4J 方式解析

  DOM4J 是第三方提供的解析

示例:

 1 package com.study.dom4jtest; 2  3 import java.io.File; 4 import java.util.Iterator; 5 import java.util.List; 6  7 import org.dom4j.Attribute; 8 import org.dom4j.Document; 9 import org.dom4j.DocumentException;10 import org.dom4j.Element;11 import org.dom4j.io.SAXReader;12 13 /**14  * DOM4J 方式解析15 */16 public class DOM4JTest {17 18   public static void main(String[] args) {19     // 解析books.20     // 创建SAXReader的对象reader21     SAXReader reader = new SAXReader();22     try {23       // 通过reader对象的read方法加载books.24       Document document = reader.read(new File("books.));25       // 通过document对象获取根节点bookstore26       Element bookStore = document.getRootElement();27       // 通过element对象的elementIterator方法获取迭代器28       Iterator it = bookStore.elementIterator();29       // 遍历迭代器,获取根节点中的信息(书籍)30       while (it.hasNext()) {31       System.out.println("=====开始遍历某一本书=====");32       Element book = (Element) it.next();33       // 获取book的属性名以及 属性值34       List<Attribute> bookAttrs = book.attributes();35       for (Attribute attr : bookAttrs) {36        System.out.println("属性名:" + attr.getName() + "--属性值:" + attr.getValue());37        }38       //解析子节点的信息39       Iterator itt = book.elementIterator();40       while (itt.hasNext()) {41        Element bookChild = (Element) itt.next();42        System.out.println("节点名:" + bookChild.getName() + "--节点值:" + bookChild.getStringValue());43        }44       System.out.println("=====结束遍历某一本书=====");45       }46 47     } catch (DocumentException e) {48       e.printStackTrace();49     }50   }51 52 }

五、四种解析方式比较分析

基础方法:DOM(平台无关的官方解析方式)、SAX(基于事件驱动的解析方式)
扩展方法:JDOM、DOM4J(在基础的方法上扩展出的,只有在java中能够使用的解析方法)

##解析速度的分析 

 

SAX>DOM>DOM4J>JDOM

JUnit是Java提供的一种进行单元测试的自动化工具。测试方法可以写在任意类中的任意位置。使用JUnit可以没有main()入口进行测试。
DOM4J在灵活性和对复杂DOM4J的应用范围非常的广,例如在三大框架的Hibernate中是使用DOM4J的方式解析文件的。
DOM是w3c组织提供的一个官方解析方式,在一定程度上是有所应用的。
当1.JUnit:Java提供的单元测试;@Test注解;采用JUnit不需要程序入口main方法
2.性能测试结果:几kB的   DOM-33ms
  SAX-6ms
  JDOM-69ms
  DOM4J-45ms
工程右键build path --Add library--JUnit单元测试 --version:JUnit4
  DOM:33,SAX:6
  JDOM:69;DOM4J:45
  DOM 有可能溢出
多使用DOM4J