java解析xml

最近学习了xml的解析,感觉应该总结一下:

xml在开发中还是非常重要的,主要用来当做配置文件,存储和传输数据用的。所以如何来解析xml就尤为重要。

xml的解析方式有两种:dom和sax。两种方式各有优缺点:

*dom方式解析

根据xml的层级结构在内存中分配一个树形结构,把xml的标签、属性、文本都封装成对象。

缺点:如果文件过大,造成内存溢出

优点:方便实现增删改操作

**sax方式解析

采用事件驱动的方式,边读边解析

- 从上到下,一行一行解析,解析到某个对象,返回对象名称

缺点:不能实现增删改操作

优点:文件过大时,不会造成内存溢出,方便实现查询操作。


java 解析xml:java解析xml的方式称为jaxp。jaxp是javase的一部分。jaxp解析器在jdk的javax.xml.parsers包里面。这里面当然也包含了两种解析方式。

dom解析方式:

先说说jaxp创建dom解析器:

要得到dom解析器还真有点麻烦:先要创建dom解析器工厂,然后根据工厂得到dom解析器,再使用parse方法与xml连接。这样,该对象就代表了所指定的xml文件。

			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
			Document document = documentBuilder.parse(PATH);
最后得到的document就代表整个xml文件了。

回写xml:

使用dom可以对xml文件进行增删改查,当然这是在内存中进行操作的,那么如何将修改过的document写回原文件中呢?这时,就需要用到回写xml所需要的类了。

			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer =transformerFactory.newTransformer();
			transformer.transform(new DOMSource(document), new StreamResult(PATH));

这其中传的参数document就是你得到解析器时的Document对象,PATH为写回的路径。


因为上面两个操作比较固定,所以我把它们封装成了一个工具类:

public class DomUtils {
	/*
	 * 在使用该类时,请先初始化PATH,即先调用setPATH()方法。
	 * */
	private static String PATH = "";
	public static void setPATH(String path){
		PATH = path;
	}
	public static String getPATH(){
		return PATH;
	}
	//获取xml的document对象
	public static Document getDocument(){
		try {
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
			Document document = documentBuilder.parse(PATH);
			
			return document;
		} 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();
		}
		return null;
	}
	//根据document回写xml
	public static void xmlWriters(Document document){
		try{
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer =transformerFactory.newTransformer();
			transformer.transform(new DOMSource(document), new StreamResult(PATH));
		}catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

使用dom解析xml当然少不了对其内容的增删改查:

	//使用jaxp添加节点,在school标签下面再添加一个class标签
	public static void addNode() throws Exception{
		/*
		 * 1、创建解析器工厂
		 * 2、创建解析器
		 * 3、解析xml,得到document
		 * 4、得到school标签
		 * 5、创建class标签
		 * 6、创建文本
		 * 7、把文本添加到class下
		 * 8、把class添加到school下
		 * 9、回写xml
		 * */
		DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
		Document document= documentBuilder.parse("src\\01.xml");
		//4、得到school标签
		Node school= document.getElementsByTagName("school").item(0);
		//5、创建class标签
		Element class1 =document.createElement("class");
		//6、创建文本
		Text text1=document.createTextNode("shen12");
		// 7、把文本添加到class下
		class1.appendChild(text1);
		//8、吧class添加到school下
		school.appendChild(class1);
		
		//回写xml
		/*
		 * 1.创建transformerfactory的对象
		 * 2、根据transformerfactory的对象创建transformer对象
		 * 3、使用transformer的transform方法  transform(Source xmlSource, Result outputTarget) 
		 * 		传递两个参数
		 * 	  		1,DOMSource对象,以 Document Object Model(DOM)树的形式充当转换 Source 树的持有者。
		 * 			2.streamResult对象,充当转换结果的持有者,可以为 XML、纯文本、HTML 或某些其他格式的标记。
		 * */
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer=transformerFactory.newTransformer();
		transformer.transform(new DOMSource(document), new StreamResult("src\\01.xml"));
		
	}
}
	//删除节点
	public static void delNode() throws Exception{
		/*
		 * 删除第三个name标签
		 *1、创建解析器工厂
		 *2、创建解析器
		 *3、解析,得到doucment
		 *4、得到第三个标签
		 *5、得到这个标签的父标签
		 *6、通过父标签删除
		 *7、回写xml
		 *
		 * */
		DocumentBuilderFactory documentBuilderFactory= DocumentBuilderFactory.newInstance();
		DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
		Document document=documentBuilder.parse("src\\01.xml");
		NodeList nameList =document.getElementsByTagName("name");
		Node nameBy3 =nameList.item(2);
		Node namenParent =nameBy3.getParentNode();
		namenParent.removeChild(nameBy3);
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer=transformerFactory.newTransformer();
		transformer.transform(new DOMSource(document),new StreamResult("src\\01.xml"));
<pre name="code" class="java">	//使用jaxp修改节点
		public static void setNode() throws Exception{
			/*
			 *修改第二个name的名称为杨泽斌
			 *1、创建解析器工厂
			 *2、创建解析器
			 *3、解析,得到doucment
			 *4、得到name的list
			 *5、得到第二的name
			 *6、修改文本为杨泽斌
			 *7、回写xml
			 * */
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder  docmBuilder=documentBuilderFactory.newDocumentBuilder();
			Document document=docmBuilder.parse("src\\01.xml");
			NodeList nameList =document.getElementsByTagName("name");
			
			Node nameBy2=nameList.item(1);
			nameBy2.setTextContent("杨泽斌");
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer=transformerFactory.newTransformer();
			transformer.transform(new DOMSource(document), new StreamResult("src\\01.xml"));
		}
<pre name="code" class="java">	//遍历xml的所有元素名称,并打印
	public static void listNodeName() throws Exception{
		/*
		 *1、创建解析器工厂
		 *2、创建解析器
		 *3、解析,得到doucment
		 *
		 *4、得到根节点
		 *5、得到根节点的子节点
		 *6.。。。。
		 * */
		DocumentBuilderFactory documentBuilderFactory= DocumentBuilderFactory.newInstance();
		DocumentBuilder documentBuilder=documentBuilderFactory.newDocumentBuilder();
		Document document=documentBuilder.parse("src\\01.xml");
		//编写一个方法来实现递归操作
		list1(document);
		
	}
	private static void list1(Node node) {
		//判断nodetype是否为元素,打印(因为xml会解析换行和空格,而这些并不是我们想要的)
		if(node.getNodeType()==Node.ELEMENT_NODE){
			
			System.out.println(node.getNodeName());
		}
		//得到下一层的名称的list
		NodeList list =node.getChildNodes();
		//得到每一个node
		for(int i = 0; i<list.getLength();i++){
			Node node1 = list.item(i);
			//继续遍历下一层的元素
			list1(node1);
		}
		
	}

再说说sax解析:

由于sax是基于事件驱动的,遇到事件会自动执行对应方法,所以我们要做的就是改变这些方法的内容,从而使执行后产生不同的效果。

sax是边读边解析,所以:

**当解析到开始标签时候,自动执行startElement方法,该方法中的qName参数就为元素开始标签

**当解析到文本时,自动执行characters方法,该方法的三个参数可转换为String类的构造方法,用此来new String对象

**当解析到结束标签是,自动执行endElement方法,该方法中的qName参数就为元素结束标签

sax只能完成查询操作:

public class saxTest {
	public static void main(String[] args) throws Exception{
		
	/*
	 * 1、创建解析器工厂
	 * 2、创建解析器
	 * 3、执行parse方法
	 * 4、自己创建一个类,继承DefaultHandler
	 * 5、自己重写其中的三个方法:startElement方法,characters方法,endElement方法
	 * */
	SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
	SAXParser saxParser =saxParserFactory.newSAXParser();
	saxParser.parse("src\\02.xml", new MyDefault2());
	}
}

class MyDefault2 extends DefaultHandler{
	//获取name标签的值
	boolean flag = false;
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		//判断qName是否为name标签
		if("name".equals(qName)){
			flag=true;
		}
	}
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		//是Name标签则打印
		if(flag){
			System.out.println(new String(ch,start,length));
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		//重置
		flag=false;
	}
}

class MyDefault1 extends DefaultHandler{

	//以整个文档的形式打印
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		System.out.print("<"+qName+">");
	}

	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		System.out.print(new String(ch,start,length));
		
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		System.out.print("</"+qName+">");
	}
}


 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值