Java中XML的四种解析方式(DOM , SAX , JDOM , DOM4J)

本文介绍了Java中XML的四种解析方式:DOM、SAX、JDOM和DOM4J。DOM解析通过父节点和子节点逐层解析XML;SAX是事件驱动的API,通过定义处理类解析XML;JDOM使用具体类代替接口处理XML;DOM4J与JDOM相似,但提供更方便的二次迭代获取深层节点。文章详细阐述了每种方式的步骤并提供了代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文以解析如下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)方法 

  1. uri:xml文档的命名空间
  2. localName:标签的名字
  3. qName:带命名空间的标签的名字
  4. attributes:标签的属性集

    ④ endElemetn(String uri, String localName, String qName)方法, 

    ⑤ characters(char[] ch, int start, int length)方法

  1. ch:当前读取到的TextNode(文本节点)的字节数组
  2. start:字节开始的位置,为0则读取全部
  3. 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值