JavaWEB.xml解析技术SAX&DOM(学习笔记)

/*
XML语法
一个XML文件分为如下几个部分:
文档声明、元素、属性、注释、CDATA区、处理指令
*/
<?xml version=”1.0” encoding=”GB2312” standalone=”no” ?>
<?xml-stylesheet type=”text/css” href=”1.css”?>
<!--
	用户信息
-->
<用户信息>
	<用户名编号=”001”>
		<姓名>
			<![CDATA[
				刘备 //被CDATA括起来的字符浏览器会按照文本来处理
			]]>
		</姓名>
		<密码>
			1234
		</密码>
	</用户>
</用户信息>

/*
XML约束:在xml技术里,可以编写一个文档来约束一个xml文档的写法
常见的xml约束技术:
XML DTD(Document Type Definition) //浏览器默认没有开启DTD校验,DTD文件保存的时候必须要保存成utf8格式
*/
<?xml version=”1.0” encoding=”gb2312”?>
<!DOCTYPE 书架 SYSTEM “book.dtd”>  //根标签以及下面所有的元素都受到book.dtd约束
<书架>
	<书>									book.dtd:
		<书名>Java圣经</书名>				<!ELEMENT 书架 (书+)> //书可以出现多次
		<作者>Lex</作者>					<!ELEMENT 书(书名,作者,售价)>
		<售价>69.00元</售价>				<!ELEMENT 书(#PCDATA)>
	</书>									<!ELEMENT 作者(#PCDATA)>
	<书>									<!ELEMENT 售价(#PCDATA)>
		<书名>Java从入门到精通</书名>
		<作者>Lex</作者>
		<售价>50.00元</售价>
	</书>
</书架>
//利用javascript脚本校验DTD
<html>
	<head></head>
	<body>
		错误行号:<div id=”l”></div>
		错误原因:<div id=”r”></div>
	</body>
</html>
<script>
	var xmldoc = new ActiveXObject(“Microsoft.XMLDOC”);//创建解析器
	xmldoc.validateOnParse=true;//打开DTD校验
	xmldoc.load(“book.xml”); //校验的文件
	var line = xmldoc.parseError.line;
	var reason = xmldoc.parseError.reason;
	document.getElementById(“l”).innerHTML=line;
	document.getElementById(“r”).innerHTML=reason;
</script>


/*
DTD语法
1.如何在xml中引入dtd
1)外部引用
可以将dtd的约束内容写在外置的dtd文件中,这个文件后缀必须为.dtd,而文件保存时必须用utf-8编码
然后再在xml文件中使用
*/
<!DOCTYPE 根元素名称	SYSTEM 文件的位置>
//如果写的是SYSTEM表明当前引入的dtd在当前文件系统中,后面指定的位置是当前硬盘中的位置
<!DOCTYPE 文档根节点	PUBLIC “DTD名称” “DTD文件的URL”>
/*
如果写的是PUBLIC表明当前引入的dtd在网络公共位置中,后面要指明dtd的名称,及所在URL地址
2)内部引用
直接在xml中书写dtd
*/
<!DOCTYPE 根元素名称[
	DTD约束
]>
/*
2.dtd语法
1)元素约束:
存放类型:ANY/EMPTY //允许包含任意子元素、不能存放任何子元素
*/
<!ELEMENT 书架 ANY/EMPTY>
/*
约束条件:子元素的列表,将可以包含的子元素用()括起来就可以了,子元素之间可以使用”,”如果用”,”分隔表示元素必须按照顺序出现,子元素之间还可以用”|”进行分隔,表示元素出现其中之一即可
#PCDATA表明可以包含标签体
+ 表示一次或多次
* 表示0次或多次
? 表示0次或一次
也可以使用()批量设置,例:
*/
<!ELEMENT MYFILE ((title*,author?,email)*|comment)>
//2)属性约束:
<!ATTLIST 元素名	
属性名1	属性类型	属性约束
属性名2	属性类型	属性约束
......
>
/*
属性约束:
#REQUIRED  			//表明当前属性是一个必须存在的属性
#IMPLIED			//表明当前属性是一个可选的属性
#FIXED ‘固定值’		//表明当前属性具有一个固定值
‘默认值’			//表明当前属性具有一个默认值,如果给了其它值,否则就用默认值
*/
<!ATTLIST 书
	出版社 CDATA #REQUIRED
	种类 CDATA #IMPLIED
	网址 CDATA #FIXED “http://lex-wjl.rhcloud.com”
	版次	CDATA “1”
>
/*
属性类型:
CDATA			//表示属性值是一个字符串
ENUMERATED		//表示属性值是一个枚举的类型
ID				//表示属性值必须在整个文档中都是唯一的,如果有重复的ID则校验不通过ID属性的,值只能由字母,下划线开始,不能使用数字,不能出现空白字符
*/
<!ATTLIST 书
书号	ID	#REQUIRED
出版社	CDATA #REQUIRED
种类	(文学类|工具类|计算机类) #IMPLIED
网址	CDATA #FIXED “http://lex-wjl.rhcloud.com”
版次	CDATA “1”
>
<书 出版社=”黑马程序员” 种类=”计算机类” 版次=”2” 书号=”a001”>


/*
ENTITY(实体)	//所谓实体就是对内容的引用,可以简化代码的复用,实体分为参数实体和引用实体
引用实体:
*/
<!ENTITY 实体名称	“实体内容”>
&实体名称
//参数实体:在DTD中引用的实体,叫做参数实体
<!ENTITY 实体名称	“实体内容”>
%实体名称;


/*
XML编程:利用Java程序去增删改查
两种解析方式:
dom解析: 树形结构,每一个标签都是一个对象,标签体也是一个对象,根据它们的层级关系,产生一个Dom文档结构树
	优点: 十分便于进行增删改查的操作,只需解析一次,拿到dom对象后,可以重复使用此对象,可以重复使用,减少解析次数
	缺点: 第一次解析过程比较慢,需要将整个文档都解析完成后才能进行操作,需要将整个树的内容都加载都内存中来,比较耗费内存,当文档过大时这种解析方式对内存的损耗非常严重
sax解析: SAX解析分为两个角色,一个解析器,一个事件处理器,解析器会逐行扫描xml文件,扫描到文档上的任意内容都会触发到该内容对应的事件处理器上的方法
	优点: 不需要等待整个xml加载到内存,当解析到某一部分时,自动触发到对应的方法做处理,处理的效率比较高,不需要将整个文档加载到内存,对内存的消耗比较小,理论上无论多大的xml文件都能解析
	缺点: 每次解析都只能处理一次,再想处理还需要重新解析,只能进行查询不能进行增删改查的操作

基于这两种解析思想市面上就有了很多的解析API,
SUN jaxp既有dom方式也有sax方式,并且这套解析API已经加入到了J2SE的规范中,意味着不需要导入任何第三方开发包就可以直接使用这种解析方式
但是这种解析方式效率低下,没什么人用。
dom4j 可以使用dom方式高效的解析xml,Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,
dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。 Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使	用的特点。
现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
使用Dom4j开发,需下载dom4j相应的jar文件。
*/
//book.xml
<?xml version="1.0" encoding="UTF-8"?>
<书架> 
  <书> 
    <书名>Java就业培训教程</书名>  
    <作者>张孝祥</作者>  
    <售价>39.00元</售价> 
  </书>  
  <书> 
    <书名>JavaScript网页开发</书名>  
    <作者>张孝祥</作者>  
    <售价>28.00元</售价> 
  </书> 
</书架>
//sax解析:
package com.cokeer.sax;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;


public class SaxDemo1 {
	public static void main(String[] args) throws Exception {
		//1.获取解析器工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
		//2.通过工厂获取sax解析器
		SAXParser parser = factory.newSAXParser();
		//3.获取读取器
		XMLReader reader = parser.getXMLReader();
		//4.注册事件处理器
		reader.setContentHandler(new MyContentHandler2() );
		//5.解析xml
		reader.parse("book.xml");
		
		
	}
}
//实现事件处理器
class MyContentHandler implements ContentHandler{ //实现事件处理器

	public void startDocument() throws SAXException {
		System.out.println("文档解析开始了.......");
	}
	
	public void startElement(String uri, String localName, String name,
			Attributes atts) throws SAXException {
		System.out.println("发现了开始标签,"+name);
	}
	
	public void characters(char[] ch, int start, int length)
		throws SAXException {
		System.out.println(new String(ch,start,length));
	}
	
	public void endElement(String uri, String localName, String name)
		throws SAXException {
		System.out.println("发现结束标签,"+name);
	}

	
	public void endDocument() throws SAXException {
		System.out.println("文档解析结束了.......");
	}
	
//适配器设计模式,继承DefaultHandler,它方便了我们继承,想要什么重写什么就可以
class MyContentHandler2 extends DefaultHandler{
	private String eleName = null;
	private int count = 0;
	@Override
	public void startElement(String uri, String localName, String name,
			Attributes attributes) throws SAXException {
		this.eleName = name;
	}
	
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		if("书名".equals(eleName) && ++count==2){
			System.out.println(new String(ch,start,length));
		}
	}
	
	@Override
	public void endElement(String uri, String localName, String name)
			throws SAXException {
		eleName = null;
	}
	
}


//dom4j解析
package cn.cokeer.dom4j;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class Dom4jDemo1 {
	public static void main(String[] args) throws Exception {
		//获得解析器工厂
		SAXReader reader = new SAXReader();
		//获得xml文档的dom对象
		Document dom = reader.read("book.xml");
		//获得根元素
		Element root = dom.getRootElement();
		//获取书名元素,dom4j不能跨节点,必须先得到书,才能得到书名
		String bookName = root.element("书").element("书名").getText();
		System.out.println(bookName);
	}
}

//例子2:使用dom4j进行增删改查
package cn.cokeer.dom4j;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

public class Dom4jDemo2 {
	@Test
	public void test1() throws Exception {
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		//获得根元素
		Element bookFile = root.element("书");
		//给书元素添加属性 "出版社" 值为 "传智播客出版社"
		bookFile.addAttribute("出版社", "传智播客出版社");
		//获取元素出版社的值
		String cbs = bookFile.attributeValue("出版社");
		System.out.println(cbs);
		//获得出版社属性对象
		Attribute attr = bookFile.attribute("出版社");
		//移除attr属性
		attr.getParent().remove(attr);
		//将修改写入xml文件
		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"));
		writer.write(dom);
		writer.close();
	}
	@Test
	public void add()throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		//凭空创建<特价>节点,设置标签体
		Element price2Ele = DocumentHelper.createElement("特价");
		price2Ele.setText("40.0元");
		//获取父标签<书>将特价节点挂载上去
		Element bookEle = root.element("书");
		bookEle.add(price2Ele);
		
		//将内存中的dom树会写到xml文件中,从而使xml中的数据进行更新
//		FileWriter writer = new FileWriter("book.xml");
//		dom.write(writer);
//		writer.flush();
//		writer.close();
		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
		writer.write(dom);
		writer.close();
	}
	
	@Test
	public void del() throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		
		//获取特价元素对象
		Element price2Ele = root.element("书").element("特价");
		price2Ele.getParent().remove(price2Ele); //删除特价元素

		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
		writer.write(dom);
		writer.close();
	}
	@Test
	public void update()throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		
		//获取售价元素更改其值为41元
		root.element("书").element("售价").setText("41.0元");
		
		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
		writer.write(dom);
		writer.close();
	}
	@Test
	public void find() throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		
		//获得所有元素保存到List集合中
		List<Element> list =  root.elements();
		Element book2Ele = list.get(1);
		System.out.println(book2Ele.element("书名").getText());
		
	}
}


转载于:https://my.oschina.net/kissbaby/blog/370279

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值