在项目开发中,经常会涉及到许许多多和数据处理有关的环节,如数据采集、数据解析、数据存储、数据格式化等等,本文与大家分享交流java关于数据解析的相关知识。大家知道,实际项目中,在交互时使用较多的数据格式有json、xml(可扩展标记语言)。对于json格式数据的解析,已在《Java常用数据结构基础知识总结(二)》中与大家做了基本的介绍,有兴趣的朋友可以查阅。本文主要和大家一起学习解析XML格式数据的几种常用方法。
一、前期文档准备
首先我们准备好需要解析的XML文档,并针对该文档生成相应的Java实体类:
xml文档:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1">
<name>西游记</name>
<author>吴承恩</author>
<dynasty>明代</dynasty>
</book>
<book id="2">
<name>红楼梦</name>
<author>曹雪芹</author>
<dynasty>清代</dynasty>
</book>
<book id="3">
<name>三国演义</name>
<author>罗贯中</author>
<dynasty>元末明初</dynasty>
</book>
<book id="4">
<name>水浒传</name>
<author>施耐庵</author>
<dynasty>元末明初</dynasty>
</book>
</bookstore>
编写对应java实体类Book:
package com.ldl.xml;
public class Book {
private int id;
private String name;
private String author;
private String dynasty;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDynasty() {
return dynasty;
}
public void setDynasty(String dynasty) {
this.dynasty = dynasty;
}
@Override
public String toString() {
return "Book [id=" + id + ", name=" + name + ", author=" + author + ", dynasty=" + dynasty + "]";
}
}
二、各解析方式及说明
接下来我们介绍具体的解析方法:
方法一、DOM(文档对象模型)解析方式
原理:将XML文档数据转换成一个DOM树形结构数据,使用DOM相关接口操作DOM树。
package com.ldl.xml;
import java.util.ArrayList;
import java.util.List;
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;
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{
document = db.parse(fileName);
NodeList bookList = document.getElementsByTagName("book");
books = new ArrayList<Book>();
for(int i=0;i<bookList.getLength();i++){
Book book = new Book();
Node node = bookList.item(i);
NamedNodeMap namedNodeMap = node.getAttributes();
String id = namedNodeMap.getNamedItem("id").getTextContent();
book.setId(Integer.parseInt(id));
NodeList cList = node.getChildNodes();
ArrayList<String> contents = new ArrayList<>();
for(int j=1;j<cList.getLength();j+=2){
Node cNode = cList.item(j);
String content = cNode.getFirstChild().getTextContent();
contents.add(content);
}
book.setName(contents.get(0));
book.setAuthor(contents.get(1));
book.setDynasty(contents.get(2));
books.add(book);
}
return books;
}
public static void main(String args[]){
String fileName = "src/books.xml";
System.out.println("---ReadXmlByDom---");
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();
}
}
}
运行效果:
方法浅析:首先指定需要解析的XML文档,并转换为文档(Document)对象,然后利用文档对象获取节点(子节点),将获取到的值添加到封装好的Book对象中。
方法二、JDOM解析方式
原理:JDOM可以理解为Java语言专门用来读写XML的一种组件。
package com.ldl.xml;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
public class ReadXMLByJDom {
private List<Book> books = null;
private Book book = null;
@SuppressWarnings("unchecked")
public List<Book> getBooks(String fileName){
SAXBuilder saxBuilder = new SAXBuilder();
try {
Document document = saxBuilder.build(new FileInputStream(fileName));
Element rootElement = document.getRootElement();
List<Element> bookList = rootElement.getChildren();
books = new ArrayList<Book>();
for(Element bookElement : bookList){
book = new Book();
List<Attribute> bookAttributes = bookElement.getAttributes();
for(Attribute attribute : bookAttributes){
if(attribute.getName().equals("id")){
String id = attribute.getValue();
book.setId(Integer.parseInt(id));
}
}
List<Element> children = bookElement.getChildren();
for(Element child : children){
if(child.getName().equals("name")){
String name = child.getValue();
book.setName(name);
}else if(child.getName().equals("author")){
String author = child.getValue();
book.setAuthor(author);
}else if(child.getName().equals("dynasty")){
String dynasty = child.getValue();
book.setDynasty(dynasty);
}
}
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/books.xml";
System.out.println("---ReadXmlByJDom---");
List<Book> books= new ReadXMLByJDom().getBooks(fileName);
for(Book book : books){
System.out.println(book);
}
}
}
运行效果:
方法浅析:首先指定需要解析的XML文档,并利用SAXBuilder解析器将其通过流的形式转换为文档(Document)对象,然后利用文档对象获取节点(子节点),将获取到的值添加到封装好的Book对象中。
方法三、DOM4j解析方式
原理:与DOM基本相似。
package com.ldl.xml;
import java.io.File;
import java.util.ArrayList;
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 ReadXMLByDom4j {
private List<Book> bookList = null;
private Book book = null;
@SuppressWarnings("rawtypes")
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();
List<Attribute> attributes = bookElement.attributes();
for(Attribute attribute : attributes){
if(attribute.getName().equals("id")){
String id = attribute.getValue();
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")){
String name = child.getStringValue();
book.setName(name);
}else if(nodeName.equals("author")){
String author = child.getStringValue();
book.setAuthor(author);
}else if(nodeName.equals("dynasty")){
String dynasty = child.getStringValue();
book.setDynasty(dynasty);
}
}
bookList.add(book);
}
} 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/books.xml");
System.out.println("---ReadXmlByDom4j---");
List<Book> bookList = new ReadXMLByDom4j().getBooks(file);
for(Book book : bookList){
System.out.println(book);
}
}
}
运行效果:
方法浅析:与JDOM方法思路基本一致。
方法四、SAX解析方式
原理:SAX分析器通过事件触发的形式,实现对XML文档数据的访问和操作。
工具类:
package com.ldl.xml;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SAXParseHandler extends DefaultHandler{
private List<Book> list;
private Book book;
private String content = null;
@Override
public void startDocument() throws SAXException {
super.startDocument();
list = new ArrayList<Book>();
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
@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();
String id = attributes.getValue("id");
book.setId(Integer.parseInt(id));
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if(qName.equals("name")){
book.setName(content);
}else if(qName.equals("author")){
book.setAuthor(content);
}else if(qName.equals("dynasty")){
book.setDynasty(content);
}else if(qName.equals("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);
}
public List<Book> getBooks(){
return list;
}
}
具体实现:
package com.ldl.xml;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class ReadXmlBySAX {
private static List<Book> books = 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/books.xml");
System.out.println("---ReadXmlBySAX---");
for(Book book:books){
System.out.println(book);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行效果:
方法浅析:SAX解析器采用流式处理方式,每读取XML的一个根节点(子节点)都会触发事件,直到整个文档解析完毕。
几种方法解析XML各有优劣,关于方法效率的对比,大家可以查阅资料深入研究,毕竟用到解析XML的项目相对较少,在此不做赘述。