本文以解析如下xml为例:
<?xml version="1.0" encoding="GB2312"?>
<china>
<province name="河北省">
<city>石家庄</city>
<city>邯郸</city>
<city>唐山</city>
<city>张家口</city>
<city>廊坊</city>
<city>保定</city>
<city>承德</city>
</province>
<province name="辽宁省">
<city>沈阳</city>
<city>大连</city>
<city>鞍山</city>
<city>抚顺</city>
<city>铁岭</city>
</province>
<province name="山东省">
<city>济南</city>
<city>青岛</city>
<city>威海</city>
<city>烟台</city>
<city>潍坊</city>
</province>
</china>
一、DOM:
该方式的思路是以父节点,子节点的形式,逐层去解析xml标签里的各层。
步骤:
1、首先导入xml文件;
2、通过父节点的名称(“province”)获取一个父节点数组(List)
3、利用for循环遍历每个父节点。
3.1.1、利用NameNodeMap类将父节点里的属性放入一个数组中 attr_List。
3.1.2、遍历attr_List数组,输出每个父节点的属性值
3.2.1、利用.getChildNodes()方法,获取父节点下的子节点集合child_List.
3.2.2、循环遍历出 子节点名+子节点值(此处应判断节点是否为元素节点Node.ELEMENT_NODE)
package com.yan.xml.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
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;
public class DomTest {
public static void main(String[] args) {
File file = new File("cities.xml");
FileInputStream fis = null;
try {
//导入需要解析的xml文件
fis = new FileInputStream(file);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(fis);
//通过父节点的名称(“province”)获取一个父节点数组(List)
NodeList node_List = document.getElementsByTagName("province");
System.out.println("该文件中共包括" + node_List.getLength() + "个省");
//利用for循环遍历每个父节点。
for (int i = 0; i < node_List.getLength(); i++) {
System.out.println("===========开始解析第" + (i + 1)
+ "个省================");
Node book = node_List.item(i);
//利用NameNodeMap类将父节点里的属性放入一个数组中 attr_List。
NamedNodeMap attr_List = book.getAttributes();
System.out.println("此省标签共有" + attr_List.getLength() + "个属性");
//遍历attr_List数组,输出每个父节点的属性值
for (int j = 0; j < attr_List.getLength(); j++) {
Node attribures = attr_List.item(j);
System.out.println("属性名 :" + attribures.getNodeName()
+ " , 属性值 :" + attribures.getNodeValue());
}
//利用.getChildNodes()方法,获取父节点下的子节点集合child_List.
NodeList child_List = book.getChildNodes();
System.out.println("子节点共有 " + child_List.getLength() + " 个");
//循环遍历出 子节点名+子节点值(此处应判断节点是否为元素节点Node.ELEMENT_NODE)
for (int n = 0; n < child_List.getLength(); n++) {
Node child = child_List.item(n);
if (child.getNodeType() == Node.ELEMENT_NODE) {
System.out.println("第" + (n + 1)/2 + "个子节点的节点名 :"
+ child.getNodeName() + " ,节点值:"
+ child.getFirstChild().getNodeValue());
}
}
System.out.println("===========第" + (i + 1)
+ "个省解析完毕================");
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} 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();
} finally {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
二、SAX:
此方法是利用事件驱动的XMl API。要先将xml的各个节点名放入一个javabean文件中,通过对xml文件逐行解析,来将对应的值放入到对应javabean的set()方法中,最后统一输出的。
步骤
1、准备一个xml节点对应的javabean
2、定义一个SAXparseHandler类(集成自DefaultHandle)重写其中的
① startDocument()方法
② endDocument()方法
③ startElement(String uri, String localName, String qName,Attributes attributes)方法
- uri:xml文档的命名空间
- localName:标签的名字
- qName:带命名空间的标签的名字
- attributes:标签的属性集
④ endElemetn(String uri, String localName, String qName)方法,
⑤ characters(char[] ch, int start, int length)方法
- ch:当前读取到的TextNode(文本节点)的字节数组
- start:字节开始的位置,为0则读取全部
- length:当前TextNode的长度
3.1、得到xml文件对应的资源,可以是xml的输入流,文件和uri
3.2、得到SAX解析工厂(SAXParserFactory
)
3.3、由解析工厂生产一个SAX解析器(SAXParser
)
3.4、传入输入流和handler给解析器,调用parse()
解析
代码:
javabean
package com.yan.xml.test.sax.province;
import java.util.ArrayList;
import java.util.List;
public class Province {
private String name;
private List<String> city;
//xml中有多个city标签,故放进list中
private List<String> list=new ArrayList<String>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getCity() {
return city;
}
public void setCity(String city) {
list.add(city);
this.city = list;
}
}
SAXparseHandle:
package com.yan.xml.test.sax.province;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/*
* 步骤:
* 1先执行第一步 startDocument()
* 2 判断是否存在"province"标签,若存在则执行第二步startElement,否则直接结束。
* 3接着进行第三步characters,得到各节点的值value
* 4 判断是否存在子节点,若存在则循环到第二步startElement开始,否则进行第四步endElement
* 5最后进行第五步,直至结束。
*/
public class SaxParseHandler extends DefaultHandler{
private List<Province> pro_List=new ArrayList<Province>();
private Province province=null;
private int provIndex=0;
private String value="";
//用于SAXTest时用增强for循环的方式进行遍历
public List<Province> getProvinceList(){
return pro_List;
}
//最先执行:第一步
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
System.out.println("=====================解析开始=======================");
}
//最后执行:第五步
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
System.out.println("=====================解析结束=======================");
}
//其次执行:第二步
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
//如果标签名是"province"则进行过解析
if(qName.equals("province")){
provIndex++;//统计"province"出现次数
province=new Province();//将javabean实例化
System.out.println("+++++++++开始解析第" + provIndex + "个省份+++++++++++");
for(int i=0;i<attributes.getLength();i++){
System.out.println("属性名 : "+ attributes.getQName(i) +",属性值 :"+attributes.getValue(i));
province.setName(attributes.getValue(i)); //赋值javabean
}
}
}
//第四步
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
/* 对javabean里面的不同属性进行赋值*/
if(qName.equals("province")){
pro_List.add(province);
province=null;
System.out.println("+++++++++第" + provIndex + "个省份解析结束+++++++++++");
}else if(qName.equals("city")){
province.setCity(value);
}
}
//第三步
@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);
if(!value.trim().equals("")){
System.out.println("节点值 :"+value);
}
}
}
SAXTest:
package com.yan.xml.test.sax.province;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class SAXTest {
public static void main(String[] args){
// 1. 得到SAX解析工厂
SAXParserFactory saxpf=SAXParserFactory.newInstance();
try {
// 2. 让工厂生产一个sax解析器
SAXParser saxp=saxpf.newSAXParser();
// 3. 传入输入流和handler,解析
SaxParseHandler handler=new SaxParseHandler();
saxp.parse("cities.xml", handler);
// 4.将xml解析的数据输出
for(Province province:handler.getProvinceList()){
System.out.println("---------输出开始-------------");
System.out.println(province.getName());
List<String> list=province.getCity();
Iterator it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
System.out.println("---------输出结束-------------");
}
} 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();
}
}
}
ps:推荐一篇文章其中有具体的SAX原理
https://blog.youkuaiyun.com/ydxlt/article/details/50183693
三、JDOM:(面向JAVA)
此方式就是利用具体类去替代之前的接口。(例如:Element , Attributes)
步骤:
1、获取xml文件
2、创建一个SAXBuilder对象
3、利用SAXBuilder的builer()方法,将xml文件加载到SAXBuilder里面
4、获取根节点
5、获取根节点里面的子节点集合
6、遍历
6.1、遍历属性 Attributes
6.2、遍历节点Element
package com.yan.xml.test.jdom;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
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;
public class JDomTest {
public static void main(String[] args){
// 创建一个输入流,将xml文件加载到输入流中
File file=new File("cities.xml");
InputStream ins=null;
try {
ins=new FileInputStream(file);
//1.创建一个SAXBuilder的对象
SAXBuilder builder=new SAXBuilder();
//2.通过saxBuilder的build方法,将输入流加载到saxBuilder中
Document document=builder.build(ins);
//3.通过document对象获取xml文件的根节点
Element root=document.getRootElement();
//4.获取根节点下的子节点的List集合
List<Element> list=root.getChildren();
//遍历
for(Element element : list){
System.out.println("=============开始解析=================");
//获取父节点属性
List<Attribute> attr_List=element.getAttributes();
for(Attribute attributes :attr_List){
System.out.println("属性名 :"+ attributes.getName() +",属性值 :"+attributes.getValue());
}
//获取子节点属性
List<Element> child_List=element.getChildren();
for(Element child_element : child_List){
System.out.println("节点名 : "+ child_element.getName() +",节点值 :"+child_element.getValue());
}
System.out.println("=============解析完成=================");
}
} 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();
}finally{
try {
ins.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
四、DOM4J:(面向JAVA):
总体步骤与JDOM类似。
区别在于此方式在获取 "根节点" 后进行 “第一次迭代”得到下层节点的属性 后 再继续进行 “第二次迭代” 以获取更底层节点。
package com.yan.xml.test.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){
File file=new File("cities.xml");
SAXReader saxRead=new SAXReader();
try {
Document document=saxRead.read(file);
Element root=document.getRootElement();
Iterator<Element> it=root.elementIterator();
while(it.hasNext()){
Element element=it.next();
System.out.println("======开始解析===========");
List<Attribute> child_Attr=element.attributes();
for(Attribute attribute : child_Attr){
System.out.println("属性名 : "+ attribute.getName() +",属性值 :"+attribute.getValue());
}
Iterator<Element> child_Node=element.elementIterator();
while(child_Node.hasNext()){
Element child_Element=child_Node.next();
System.out.println("节点名 : "+ child_Element.getName()+",节点值 :"+ child_Element.getStringValue());
}
System.out.println("======解析完成===========");
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ps:四种方式的优缺点,建议读一下链接的文章。
https://blog.youkuaiyun.com/shijinupc/article/details/7653945