四种常见的XML解析方式
1.XML语言简介
XML即可扩展的标记语言,可以定义语义标记(标签),是元标记语言。XML不像超文本标记语言HTML,HTML只能使用规定的标记,对于XML,用户可以定义自己需要的标记。树状模型。
XML(eXtensible Markup Language)和HTML(Hyper Text Markup Language)师出同门。
使用XML的原因:不同软件之间(订票和支付)、不同平台(Mac和Windows)之间的数据通信、不同平台间的数据共享(网站和手机APP),用相同的XML文件将不同的东西联系起来。
2.XML文件解析的四种方式
2.1 DOM解析
DOM,Document Object Model,文档对象模型。DOM是html和xml文档的编程接口规范,和平台、语言是无关的。利用DOM规范,能够实现DOM 文档和xml之间的相互转换,遍历、操作相应DOM文档的内容。DOM规范的核心就是树模型。全部读取之后再解析
2.2 JDOM解析
JDOM是Java和DOM的结合体。JDOM 致力于建立一个完整的基于 Java 平台的、通过 Java 代码来访问、操作并输出 XML 数据。JDOM是用Java语言读、写、操作XML的新API函数。简单、高效、优化。
2.3 SAX解析
SAX,Simple API For XML。非W3C官方所提供的标准,“民间”的事实标准。SAX在概念上与DOM完全不同。非文档驱动,是事件驱动的。事件驱动:一种基于回调机制的程序运行方法。由外至内一层一层解析。
2.4 DOM4j解析
dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。性能优异功能强大简单易用开放源代码。
2.5 目的
获取XML文件中的所有数据。
节点类型 NodeType Named Content nodeName返回值 nodeValue的返回值
Element 1 ELEMENT_NODE Element name null
Attr 2 ATTRIBUTE_NODE 属性名称 属性值
Text 3 TEXT_NODE #text 节点内容
3.XML解析具体实例
3.1 DOM解析实例
1.创建一个DocumentBuilderFactory的对象
2.创建一个DocumentBuilder对象,处理异常
3.通过DocumentBuilder的parse(String fileName)方法解析xml文件
4.返回一个返回org.w3c.dom.Document的对象
5.通过getElementsByTagName获取xml中所有book节点->Booklist
6.通过nodelist的getLength方法获取book节点的个数
7.遍历每一个book节点{
通过nodelist的item方法获取每一个节点
获取每一个节点的所有属性值
遍历所有属性值
}
8.或者通过ELement直接获取属性值,前提是知道属性名
解析获取属性值
见代码:code-1
解析获取子节点
见代码:code-2
3.2 JDOM解析实例(非JAVA官方的解析)
1.JDOM需要导入相应的jar包
2.创建一个SAXBuilder对象
3.创建一个输入流,将books.xml文件加载到输入流中
4.通过saxBuilder的build方法将输入流加载到saxBuilder中
5.通过Document的getRootElement获取xml文件的根节点
6.通过root的getChildren获取根节点的子节点的list集合
解析获取属性和子节点
见代码:code-4
用JDOM解析时的乱码问题:
首先修改XML文件的编码方式encoding=“UTF-8”
不修改XML文件,修正编码问题:使用InputStreamReader输入流
InputStreamReader isr = new InputStreamReader(in,”UTF-8”);
3.3 SAX解析实例
handler–startElement–endElement
通过SAXParserFactory的静态newInstance方法创建factory实例
通过factory的newSAXParser()方法创建parse实例
创建一个类继承自DefaultHandler重写方法进行业务处理并创建实例
将实例传入方法中
解析获取属性和子节点
见代码:code-3
3.4 DOM4j解析实例
1.DOM4j是非官方的解析方式要导入jar包
2.创建SAXReader对象
3.通过reader的read方法加载books.xml文件
4.获取根节点
5.获取子节点
6.获取子节点的属性和属性值
7.获取子节点的节点和节点值
代码见Code-5
4.四种XML解析方式比较
基础方法:DOM和SAX,无需导入jar包
DOM:和平台无关,解析开始将XML 文件全部读入内存
SAX:基于事件驱动的解析方式,遇到XML的内容触发方法解析
扩展方法:JDOM和DOM4j,需导入jar包,基于java平台
DOM优点:形成树结构,直观,容易理解,代码容易编写
解析过程中树结构保留在内存中,便于修改
DOM缺点:XML文件较大时,对内存耗费较大,容易影响解析性能内存溢出
SAX优点:采用事件驱动模式,对内存耗费小,适用于只需XML中数据情况
SAX缺点:编码不易,很难同时访问同一个XML文件的多处数据
Code-1:DOM解析XML获取属性值(两种方法)
DOMTest.java
package com;
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 {
public static void main(String[] args) {
/**
* @author Stella
*/
//创建一个DocumentBuilderFactory的对象
DocumentBuilderFactory bdf = DocumentBuilderFactory.newInstance();
//创建一个DocumentBuilder对象,处理异常
try {
DocumentBuilder bd = bdf.newDocumentBuilder();
//通过DocumentBuilder的parse(String fileName)方法解析xml文件
//返回org.w3c.dom.Document的对象
Document doc = bd.parse("web/books.xml");
//通过getElementsByTagName获取xml中所有book节点->Booklist
NodeList booklist = doc.getElementsByTagName("book");
//通过nodelist的getLength方法获取book节点的个数
System.out.println("一共有"+booklist.getLength()+"本书");
//遍历每一个book节点
for (int i = 0;i < booklist.getLength(); i++){
//通过nodelist的item方法获取每一个节点
Node node = booklist.item(i);
//获取每一个节点的所有属性值
NamedNodeMap attr = node.getAttributes();
//遍历所有属性值
System.out.println("第"+(i+1)+"本书有"+attr.getLength()+"个属性");
for (int j = 0; j < attr.getLength(); j++){
//通过item方法获取节点属性,可以看到返回值依然是节点
//Element、attr、Text都是节点
Node att = attr.item(j);
String name = att.getNodeName();
String value = att.getNodeValue();
System.out.println("属性名:"+name+"----属性值:"+value);
}
//通过ELement直接获取属性值,前提是知道属性名
Element attrELe = (Element) booklist.item(i);
String eleValue = attrELe.getAttribute("id");
System.out.println("属性ID的属性值为:"+eleValue);
Element attrELe1 = (Element) booklist.item(i);
String eleValue1 = attrELe1.getAttribute("id");
System.out.println("属性name的属性值为:"+eleValue1);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
}catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Code-2:java解析XML获取节点名和节点值
DOMTest .java
package com;
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 {
public static void main(String[] args) {
//创建一个DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("web/books.xml");
NodeList booklist = doc.getElementsByTagName("book");
//遍历每一个book子节点
for (int i = 0; i < booklist.getLength(); i++){
Node book = booklist.item(i);
NodeList childNodes = book.getChildNodes();
System.out.println("第"+(i+1)+"本书的子节点个数为:"+childNodes.getLength());
for (int j = 0; j < childNodes.getLength(); j++){
Node child = childNodes.item(j);
if(child.getNodeType()==Node.ELEMENT_NODE){
//获取ELement类型的类型名
String name = child.getNodeName();
//Element类型的getNodeValue返回值是null
String value = child.getTextContent();
System.out.println("子节点名称:"+name+" 子节点的值:"+value);
//也可以通过获取子节点的第一个节点来
String valueContent = child.getFirstChild().getNodeValue();
System.out.println("子节点名称:"+name+" 子节点的值:"+valueContent);
}
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
}catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Code-3:SAX解析XML获取属性名、节点名和节点值
SAXTest.java
package com;
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 com.sun.handler.SAXParseHandler;
public class SAXTest {
public static void main(String[] args) {
//1首先获取一个SAXFactory的实例factory
SAXParserFactory factory = SAXParserFactory.newInstance();
//2通过factory获取SAXParser的实例
//2创建一个SAXParseHandler的实例
SAXParseHandler phandler = new SAXParseHandler();
try {
SAXParser parser = factory.newSAXParser();
parser.parse("web/books.xml", phandler);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
SAXParseHandler.java
package com.sun.handler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SAXParseHandler extends DefaultHandler{
int bookIndex = 0;
//重写遍历xml文件的开始标签方法//解析xml元素
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
//调用父类DefaultHandler的startElement方法
super.startElement(uri, localName, qName, attributes);
if(qName.equals("book")){
/**
* 已知属性名称,根据属性名称获取属性值
* String value = attributes.getValue("id");
* System.out.println("book的属性值是:"+value);
*/
bookIndex++;
System.out.println("第" + bookIndex + "本书遍历开始");
//不知道属性名称和个数,通过attribute的方法来得到
for (int i = 0; i < attributes.getLength(); i++){
String name = attributes.getQName(i);
String value = attributes.getValue(i);
System.out.println("第" + ( i + 1 ) + "属性名称:" + name + "属性值" + value);
}
}else if(!(qName.equals("book")||qName.equals("bookstore"))){
System.out.print("节点名:" + qName);
}
}
//重写遍历xml文件的结束标签方法
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
//判断是否针对一本书已经结束
if(qName.equals("book")){
System.out.println("第" + bookIndex + "本书遍历结束");
}
}
//重写标识xml文件解析开始方法
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("SAX解析开始");
}
//重写标识xml文件解析结束方法
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("SAX解析结束");
}
//重写获取节点值的方法
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
//ch是整个books.xml的的内容
String value = new String(ch, start, length);
if(!value.trim().equals("")){
System.out.println("节点值:" + value.trim());
}
}
}
通过java类实现解析xml文件的时候保留xml文件的树结构:
创建Book.java
package com.sun.handler;
public class Book {
private String id;
private String name;
private String author;
private String year;
private String price;
private String language;
public String getId() {
return id;
}
public void setId(String 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 getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String toString() {
return super.toString();
}
}
在SAXParseHandler添加内容
SAXParseHandler.java
package com.sun.handler;
import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SAXParseHandler extends DefaultHandler{
int bookIndex = 0;
String value = new String();
Book book = null;
private ArrayList<Book> booklist = new ArrayList<Book>();
public ArrayList<Book> getBooklist() {
return booklist;
}
//重写遍历xml文件的开始标签方法//解析xml元素
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
//调用父类DefaultHandler的startElement方法
super.startElement(uri, localName, qName, attributes);
if(qName.equals("book")){
book = new Book();
/**
* 已知属性名称,根据属性名称获取属性值
* String value = attributes.getValue("id");
* System.out.println("book的属性值是:"+value);
*/
bookIndex++;
System.out.println("第" + bookIndex + "本书遍历开始");
//不知道属性名称和个数,通过attribute的方法来得到
for (int i = 0; i < attributes.getLength(); i++){
String name = attributes.getQName(i);
String value = attributes.getValue(i);
System.out.println("第" + ( i + 1 ) + "属性名称:" + name + "属性值" + value);
if(attributes.getQName(i).equals("id")){
book.setId(value);
}
}
}else if(!(qName.equals("book")||qName.equals("bookstore"))){
System.out.print("节点名:" + qName);
}
}
//重写遍历xml文件的结束标签方法
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
//判断是否针对一本书已经结束
if(qName.equals("book")){
//结束上一个book节点,清空全局book的内容,便于对下一个book进行记录
//如何保存上一个book的内容??
//用arraylist全局保存
booklist.add(book);
book = null;
System.out.println("第" + bookIndex + "本书遍历结束");
}else if(qName.equals("name")){
book.setName(value);
}else if(qName.equals("author")){
book.setAuthor(value);
}else if(qName.equals("year")){
book.setYear(value);
}else if(qName.equals("language")){
book.setLanguage(value);
}else if(qName.equals("price")){
book.setPrice(value);
}else if(qName.equals("id")){
book.setId(value);
}
}
//重写标识xml文件解析开始方法
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("SAX解析开始");
}
//重写标识xml文件解析结束方法
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("SAX解析结束");
}
//重写获取节点值的方法
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
//ch是整个books.xml的的内容
value = new String(ch, start, length);
if(!value.trim().equals("")){
System.out.println("----节点值:" + value.trim());
}
}
}
Code-4:
package com.JDOMtest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.AttributedCharacterIterator.Attribute;
import java.util.List;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
public class JDOMTest {
public static void main(String[] args) {
//1.创建一个SAXBuilder对象
SAXBuilder saxBuilder = new SAXBuilder();
File file = new File("web/books.xml");
try {
if(!file.exists()){
file.createNewFile();
}
//2.创建一个输入流,将books.xml文件加载到输入流中
FileInputStream in = new FileInputStream(file);
//3.通过saxBuilder的build方法将输入流加载到saxBuilder中
Document doc = saxBuilder.build(in);
//4.通过Document的getRootElement获取xml文件的根节点
Element root = doc.getRootElement();
//5.通过root的getChildren获取根节点的子节点
List<Element> bookList = root.getChildren();
System.out.println("一共有" + bookList.size() + "本书");
//获取book的属性
for (int i = 0; i < bookList.size(); i++){
Element book = bookList.get(i);
List<org.jdom2.Attribute> attr = book.getAttributes();
System.out.println("第" + (i + 1) +"本书" + attr.size() + "个属性");
for (int j = 0 ;j < attr.size(); j++){
System.out.print("属性名为:" + attr.get(j).getName());
System.out.println("----属性值为:" + attr.get(j).getValue());
}
}
//获取book的节点和节点值
for (int i = 0; i < bookList.size(); i++){
Element book = bookList.get(i);
List<Element> bookElement = book.getChildren();
System.out.println("第" + (i + 1) + "本书有" + bookElement.size() + "个节点");
for (int j = 0; j < bookElement.size(); j++){
String name = bookElement.get(j).getName();
String value = bookElement.get(j).getValue();
System.out.print(" 第" + (j+1) + "个----节点名:" + name);
System.out.println("----节点值:" + value);
}
}
//foreach循环解析
for (Element book:bookList){
System.out.println("\n----开始解析第" + (bookList.indexOf(book) + 1) + "本书");
List<org.jdom2.Attribute> attrs = book.getAttributes();
for (org.jdom2.Attribute attr:attrs){
//获取属性名和属性值
String name = attr.getName();
String value = attr.getValue();
System.out.print(" 第" + (attrs.indexOf(attr) + 1) + "个----属性名:" + name);
System.out.println("----节点值:" + value);
}
List<Element> ele = book.getChildren();
for (Element o:ele){
String name = o.getName();
String value = o.getValue();
System.out.print(" 第" + (ele.indexOf(o) + 1) + "个----节点名:" + name);
System.out.println("----节点值:" + value);
}
System.out.println("\n----结束解析第" + (bookList.indexOf(book) + 1) + "本书");
}
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Code-5:
package com.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 {
public static void main(String[] args) {
//1.DOM4j是非官方的解析方式要导入jar包
//2.创建SAXReader对象
SAXReader reader= new SAXReader();
try {
//通过reader的read方法加载books.xml文件
Document doc = reader.read(new File("web/books.xml"));
Element root = doc.getRootElement();
List<Element> books = root.elements();
int bookSize = books.size();
System.out.println("一共有" + bookSize + "本书");
for (Element book:books){
System.out.println("第" + (books.indexOf(book) + 1) + "本书解析开始");
//获取所有属性
List<Attribute> attrs = book.attributes();
int attrSize = attrs.size();
System.out.println("\t一共有" + attrSize + "个属性:");
for (Attribute attr:attrs){
String name = attr.getName();
String value = attr.getValue();
System.out.println("\t第" + (attrs.indexOf(attr)+1)+"个属性的属性名:" + name + "-----属性值:" + value);
}
//获取所有节点
List<Element> bookEles = book.elements();
int bookEleSize = bookEles.size();
System.out.println("\t一共有" + bookEleSize + "个节点:");
for (Element ele:bookEles){
String name = ele.getName();
String value = ele.getStringValue();
System.out.println("\t第" + (bookEles.indexOf(ele)+1)+"个节点的节点名:" + name + "-----节点值:" + value);
}
System.out.println("第" + (books.indexOf(book) + 1) + "解析结束");
}
//通过迭代器来获取所有的book
Iterator<Element> it = root.elementIterator();
while(it.hasNext()){
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
Code-5:
package com.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 {
public static void main(String[] args) {
//1.DOM4j是非官方的解析方式要导入jar包
//2.创建SAXReader对象
SAXReader reader= new SAXReader();
try {
//通过reader的read方法加载books.xml文件
Document doc = reader.read(new File("web/books.xml"));
Element root = doc.getRootElement();
List<Element> books = root.elements();
int bookSize = books.size();
System.out.println("一共有" + bookSize + "本书");
for (Element book:books){
System.out.println("第" + (books.indexOf(book) + 1) + "本书解析开始");
//获取所有属性
List<Attribute> attrs = book.attributes();
int attrSize = attrs.size();
System.out.println("\t一共有" + attrSize + "个属性:");
for (Attribute attr:attrs){
String name = attr.getName();
String value = attr.getValue();
System.out.println("\t第" + (attrs.indexOf(attr)+1)+"个属性的属性名:" + name + "-----属性值:" + value);
}
//获取所有节点
List<Element> bookEles = book.elements();
int bookEleSize = bookEles.size();
System.out.println("\t一共有" + bookEleSize + "个节点:");
for (Element ele:bookEles){
String name = ele.getName();
String value = ele.getStringValue();
System.out.println("\t第" + (bookEles.indexOf(ele)+1)+"个节点的节点名:" + name + "-----节点值:" + value);
}
System.out.println("第" + (books.indexOf(book) + 1) + "解析结束");
}
//通过迭代器来获取所有的book
Iterator<Element> it = root.elementIterator();
while(it.hasNext()){
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}