Java 读取 xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1">
<name>冰与火之歌</name>
<author>乔治马丁</author>
<year>2014</year>
<price>89</price>
</book>
</bookstore>

 

这是一个简单的xml文件,根节点是bookstore,book是bookstroe的子节点,book节点有属性id ,也有子节点name author year price。子节点name author year price没有属性 ,只有值。

1、DOM: Document Object Model 文档对象模型

  DOM解析会一次性的将xml读取到内存中,并形成一个DOM树,如果xml非常大会浪费时间,对内存性能要求高。

  优点:形成树结构,直观好理解,代码更易编写,解析过程中树结构保留在内存中,方便修改。

    缺点:当xml文件较大时,对内存耗费比较大,容易影响解析性能并造成内存溢出。

package com.zhao.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.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class DOMTest {
/**
* 应用DOM方式解析XML DOM: Document Object Model 文档对象模型
* DOM解析会一次性的将xml读取到内存中,并形成一个dom树,如果xml非常大会浪费时间,对内存性能要求高
* @author zhao
* @param args
*/
public static void main(String[] args) {
// 创建一个DocumentBuilderFactory的对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
// 创建一个DocumentBuilder的对象
DocumentBuilder builder = factory.newDocumentBuilder();
// 通过DocumentBuilder对象的parse方法加载bookstroe.xml文件到当前项目下
Document document = builder.parse("bookstore.xml");
// 获取所有book节点的集合
NodeList bookList = document.getElementsByTagName("book");
// 通过NodeList的getLength方法可以获取boolList的长度
System.out.println("===========" + bookList.getLength() + "===========");
// 遍历每一个book节点
for (int i = 0; i < bookList.getLength(); i++) {

// 已经知道节点元素的属性名:
/*
* Element element=(Element) bookList.item(i); String
* id=element.getAttribute("id"); System.out.println(id);
*/
// 不知道节点元素的属性名:
// 通过item(i)方法获取一个book节点,NodeList的索引值从0开始
Node book = bookList.item(i);
// 获取book节点的所有属性集合
NamedNodeMap map = book.getAttributes();
// 遍历book的属性
System.out.println("第" + (i + 1) + "本书共有" + map.getLength() + "个属性");
for (int j = 0; j < map.getLength(); j++) {
// 通过item(j)方法获取book节点的某一个属性
Node attr = map.item(j);
// 获取属性名和属性值
System.out.println(attr.getNodeName() + "=" + attr.getNodeValue());
}
// 解析book节点的子节点
NodeList childNode = book.getChildNodes();
System.out.println(childNode.getLength());

/*
* 通过book元素的getChildNodes()得到所有子节点的集合,需要注意的是,在DOM的读取中,
* 会将空格和回车看成是text节点类型,因此需要注意区分开。通过item(index)遍历所有子节点,通过item(
* index)的getNodeName()方法还来获取子节点的名字,而获取它的属性值时,
* 要注意直接使用getNodeValue()得到的是标签的值(一般是空)因此可以使用两种方法:
* 1.使用item(index).getFirstNode().getNodeValue()来返回值(<name>冰与火之歌
* </name>中冰与火之歌是name的子节点,而且这个节点类型是text,现在我们有节点name,
* 只需要找到它的第一个节点的节点值便可以了)
* 2.使用item(index).getTextContent()来返回属性值
* 上面两种方法的区别在于在一个标签中是否包含的其他的子标签,如果有的话,那么第1个方法就仍得到null,
* 第二个方法会返会将自标签的内容一起获得。
*/
// 遍历childNode获取每个节点的节点名和节点值
for (int j = 0; j < childNode.getLength(); j++) {
Node child = childNode.item(j);
// System.out.println(child.getNodeName());
// 区分test类型的node和element类型的node
if (child.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(child.getNodeName() + "=" + child.getTextContent());
}
}

}

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

 

分析:

  DOM使用DocumenBuilder的parse方法加载xml文件到当前目录下,parse是分析的意思。首先会用到工厂模式,先生成DocumentBuilderFactory,再由其生成DocumentBuilder,DocumentBuilder.parse会返回一个Document对象,这是xml文件到Document的过程,无论使用DOM ,SAX,JDOM,DOM4J,此步骤大同小异。

  Document就是上面写好的xml文件。

  常用节点类型       nodeName      nodeValue

  Element      element Name      null

  Attr          属性名称                   属性值

  Test          #text        节点内容

  在此document中,bookstroe是节点,book是节点,name是节点,id也是节点。类似于HTML,document.getElementsByTagName("book")可以得到所有book element,book节点有属性节点Attr,有子节点Element,也有空格Text。Node是所有节点的总称,在未知节点类型时使用Node,所有有book node。

  book node的getAttributes返回属性节点的集合NamedNodeMap,进而得到其每个属性节点node,由上述可得属性名称是node.getNodeName,属性值是node.getNodeValue。

 book.getChildNodes得到子节点集合,这里我们依旧用Node此时node是element或Text,判断child.getNodeType() == Node.ELEMENT_NODE才是我们需要的子节点,对

<name>冰与火之歌</name>而言,node是name,类型是element,而element的NodeValue却不是冰与火之歌,而是null。冰与火之歌是node的子节点text。故node.getFirstNode().getNodeValue()才是我们需要的结果。

2:SAX

  优点:采用事件驱动模式,对内存耗费比较小,适用于只需要处理xml数据时。

  缺点:不易编码,很难同时访问同一个xml中的多处不通过数据

package com.zhao.sax;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

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

public class SAXTest {
/**
* 应用SAX方式解析XML
* sax解析是基于事件的解析,每解析一部分就会触发saxHandler的具体方法
* @author zhao
* @param args
*/
public static void main(String[] args) {
// 获取一个SAXParserFactory的实例
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// 通过factory获取SAXParser实例
SAXParser saxParser = factory.newSAXParser();
// 创建SAXHandler对象
SAXHandler handler = new SAXHandler();
saxParser.parse("bookstore.xml", handler);

} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

 

 

----------------------

package com.zhao.sax;

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

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

import com.zhao.entity.Book;

/**
* SAXParserHandler类的执行顺序为:startDocument()开始Xml解析--->第一行,以后每行的执行顺序为——>
* startElement()---characters()--->endElemnet()---->到最后一行的
* <bookstore>---->endDcunment()。
* 
* @author zhao
*
*/
public class SAXHandler extends DefaultHandler {
private int bookIndex = 0;
private Book book;
private String value=null;
private List<Book> books=new ArrayList<Book>();

/**
* 用于标识解析开始
*/
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
System.out.println("SAX解析开始");
}

/**
* 用于标识解析结束
*/
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
System.out.println("SAX解析结束");
for (Book book : books) {
System.out.println(book);
}
}

/**
* 用来遍历xml文件的开始标签 在开始时可用知道属性
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// 调用DefaultHandler类的startElement方法
super.startElement(uri, localName, qName, attributes);
// 开始解析book元素的属性
if ("book".equals(qName)) {
bookIndex++;
System.out.println(bookIndex + "本书开始");

book=new Book();

// 已知book元素的下属性的名称,根据属性名称获取属性值
// String id=attributes.getValue("id");
// System.out.println("id: "+id);
// 不知道book元素下的属性名称,以及个数
for (int i = 0; i < attributes.getLength(); i++) {
System.out.println(attributes.getQName(i) + ": " + attributes.getValue(i));
if ("id".equals(attributes.getQName(i))) {
book.setId(attributes.getValue(i));
}
}
} else if (!"book".equals(qName) && !"bookstore".equals(qName)) {
System.out.print(qName);
}
}

/**
* 用来遍历xml文件的结束标签
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
if ("book".equals(qName)) {
System.out.println(bookIndex + "本书结束");
books.add(book);
book=null;
value=null;
}
else if (!"bookStore".equals(qName)&&!"book".equals(qName)) {
if ("name".equals(qName)) {
book.setName(value);
}
else if ("author".equals(qName)) {
book.setAuthor(value);
}
else if("year".equals(qName)){
book.setYear(value);
}
else if ("price".equals(qName)) {
book.setPrice(value);
}
else if ("language".equals(qName)) {
book.setLanguage(value);
}
}

}

/**
* 
* @param ch
* @param start
* @param length
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
value = new String(ch, start, length).trim();
if (!value.equals("")) {
System.out.println(value);
}

}
}

 

分析:

  SAX使用SAXParser的parse方法解析xml,也是通过SAXParserFactory生成SAXParser。不同于DOMde 节点,sax采用事件驱动,要重写DefaultHandler类,在此类中指明解析xml的过程。

  重写DefaultHandler的startDocument endDocument startElement endElement characters方法。

  解析顺序为:

  startDocument()开始xml解析--》startDocument()开始<bookstore>--》startDocument()开始<book>--》startDocument()开始<name>--》~~~endDocument。

  以<>开始,以</>结束,事件驱动,读到标签开始就是startElement,读到标签结束就是endElement。在二者之间是在characters中读内容。

3:JDOM

  仅适用具体类而不适用接口,API大量使用了Colletions类

package com.zhao.jdom;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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;

import com.zhao.entity.Book;

public class JDOMTest {
/**
* 应用JDOM方式解析xml
* 
* @author zhao
* @param args
*/
public static void main(String[] args) {
// 准备工作
// 1:创建一个SAXBuilder对象
SAXBuilder saxBuilder = new SAXBuilder();
InputStream inputStream;
try {
// 创建一个输入流,把xml文件加载到输入流
inputStream = new FileInputStream("bookstore.xml");
InputStreamReader streamReader = new InputStreamReader(inputStream, "UTF-8");
// 通过saxBuilder的build方法,将输入流加载到saxBuilder中
Document doucment = saxBuilder.build(streamReader);
// 通过document对象获取xml文件的根节点
Element rootElement = doucment.getRootElement();
// 获取根节点下的子节点的List集合
List<Element> bookList = rootElement.getChildren();
// 继续进行解析
for (Element element : bookList) {
Book book = new Book();
System.out.println("开始解析" + (bookList.indexOf(element) + 1));
// Attribute id=element.getAttribute("id");
// System.out.println(id.getName()+" "+id.getValue());
// 解析book的属性
List<Attribute> attributes = element.getAttributes();
for (Attribute attribute : attributes) {
System.out.println(attribute.getName() + " " + attribute.getValue());
if ("id".equals(attribute.getName())) {
book.setId(attribute.getValue());
}
}
// 对book节点的子节点的节点名和节点值的遍历
List<Element> bookChilds = element.getChildren();
for (Element child : bookChilds) {
System.out.println(child.getName() + " " + child.getValue());
if ("name".equals(child.getName())) {
book.setName(child.getValue());
}
if ("author".equals(child.getName())) {
book.setAuthor(child.getValue());
}
if ("year".equals(child.getName())) {
book.setYear(child.getValue());
}
if ("price".equals(child.getName())) {
book.setPrice(child.getValue());
}
if ("language".equals(child.getName())) {
book.setLanguage(child.getValue());
}
}
System.out.println(book);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

 

4:DOM4J    DOM FOR JAVA

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

package com.zhao.dom4j;

import java.io.File;
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;

public class DOM4JTest {
/**
* 应用DOM4J解析xml
* 
* @author zhao
* @param args
*/
public static void main(String[] args) {
// 创建SAXReader的reader
SAXReader saxReader = new SAXReader();
try {
// 通过reader的read方法加载xml文件,获取document对象
Document document = saxReader.read(new File("bookstore.xml"));
// 通过document对象获取根节点bookstore
Element bookStore = document.getRootElement();
//通过element对象的elementIterator方法获取迭代器
Iterator iterator = bookStore.elementIterator();
//遍历迭代器,获取根节点中的信息(书籍)
while (iterator.hasNext()) {
System.out.println("开始遍历");
Element book = (Element) iterator.next();
//获取book的属性名和属性值
List<Attribute> attributes=book.attributes();
for (Attribute attribute : attributes) {
System.out.println(attribute.getName()+" "+attribute.getValue());
}
//
Iterator<Element> iterator2=book.elementIterator();
while (iterator2.hasNext()) {
Element element = (Element) iterator2.next();
System.out.println(element.getName()+" "+element.getStringValue());
}

}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

 

posted @ 2016-04-02 20:37  假寐的我  阅读(866)  评论(0编辑  收藏  举报