您的位置:首页 > 编程语言 > Java开发

Java进阶学习第六天——DOM4J入门

2016-04-18 16:07 656 查看
文档版本开发工具测试平台工程名字日期作者备注
V1.02016.04.17lutianfeinone

XML约束——schema

XML Schema 也是一种用于定义和描述 XML 文档结构与内容的模式语言,其出现是为了克服 DTD 的局限性。

schema和DTD的对比(面试题):

Schema符合XML语法结构。

DOM、SAX等XML API很容易解析出XML Schema文档中的内容。

XML Schema对
名称空间
支持得非常好。

XML Schema比XML DTD支持更多的数据类型,并支持用户自定义新的数据类型。

XML Schema定义约束的能力非常强大,可以对XML实例文档作出细致的语义限制。

XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织的标准,它正逐步取代DTD。

Schema一些概念

XML Schema 文件自身就是一个XML文件,但它的扩展名通常为
.xsd


和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为
schema


应用schema约束 开发xml 过程



编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个
URI地
址上,这个URI地址叫
namespace名称空间
,以后XML文件就可以通过这个URI(即名称空间)引用绑定指定名称空间的元素。

Schema开发步骤

开发schema约束文档

引入W3C的名称

根节点
上,使用属性
xmlns
(xml namespace)

xmlns="http://www.w3.org/2001/XMLSchema"


定义元素

<element name="书架"></element>


判断是否是复杂还是简单的元素

如果是简单 在element有属性
type="数据的类型"


如果是复杂

声明标签是复杂的元素
<complexType>


子元素之间的关系 eg:有序
<sequence>


起名:
targetNamespace
目标名称空间

值是任意的:
http://www.itcast.cn/1110


elementFormDefault :

qualified(使用) :质量好的

unqualified :质量不好的

在XML文档中引入自己编写的schema文档

引入W3C名称空间,我是实例文档。

xmlns="http://www.w3.org/2001/XMLSchema-instance"


引入自己编写的schema的文档

xmlns="http://www.itcast.cn/1110"


问题:元素上不能有相同的属性名称

解决:起别名 eg:aa

技巧:在下面出现标签的概率小起别名

引入自己编写的schema文档的地址

schemaLocation
属性是W3C提供的,如果W3C名称空间要是有别名的话,先把别名写上。

xsi:schemaLocation="名称空间   schema文件的地址"


编写属性

<attribute name="出版社" type="string" use="required" ></attribute>


name 属性名称

type 属性类型

user 属性约束



// schema 文件:
<?xml version="1.0" encoding="UTF-8"?>

<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itcast.cn/1110" elementFormDefault="qualified">

<!-- 复杂元素 -->
<element name="书架">
<!-- 复杂元素 -->
<complexType>
<!-- 有顺序的 -->
<sequence maxOccurs="unbounded">
<element name="书">
<!-- 复杂的元素 -->
<complexType>
<!-- 有顺序的 -->
<sequence>
<!-- 简单元素 -->
<element name="书名" type="string"></element>
<element name="作者" type="string"></element>
<element name="售价" type="double"></element>
<element name="简介" type="string"></element>
</sequence>

<!-- 书的属性 -->
<attribute name="出版社" type="string" use="required" ></attribute>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>


// xml 文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<书架 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.itcast.cn/1110"
xsi:schemaLocation="http://www.itcast.cn/1110 book.xsd"
>
<书 出版社="清华出版社">
<书名>javaweb开发大全</书名>
<作者>班长</作者>
<售价>99.8</售价>
<简介>这是不错啊</简介>
</书>
<书 出版社="清华出版社">
<书名>javaweb开发大全</书名>
<作者>班长</作者>
<售价>99.8</售价>
<简介>这是不错啊</简介>
</书>
<书 出版社="清华出版社">
<书名>javaweb开发大全</书名>
<作者>班长</作者>
<售价>99.8</售价>
<简介>这是不错啊</简介>
</书>
</书架>


名称空间的概念

在XML Schema中,每个约束模式文档都可以被赋以一个唯一的名称空间,名称空间用一个唯一的
URI
(Uniform Resource Identifier,统一资源标识符)表示。

在Xml文件中书写标签时,可以通过名称空间声明(xmlns),来声明当前编写的标签来自哪个Schema约束文档。如:

<itcast:书架 xmlns:itcast=“http://www.itcast.cn”>
<itcast:书>……</itcast:书>
</itcast:书架>


此处使用itcast来指向声明的名称,以便于后面对名称空间的引用。

注意:名称空间的名字语法容易让人混淆,尽管以 http:// 开始,那个 URL** 并不指向一个包含模式定义的文件**。事实上,这个
URL:http://www.itcast.cn
根本没有指向任何文件,只是一个分配的名字。

使用名称空间引入Schema

为了在一个XML文档中声明它所遵循的Schema文件的具体位置,通常需要在Xml文档中的根结点中使用
schemaLocation
属性来指定,例如:

<itcast:书架 xmlns:itcast="http://www.itcast.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“http://www.itcast.cn book.xsd">


schemaLocation此属性有两个值。

第一个值是需要使用的命名空间。

第二个值是供命名空间使用的 XML schema 的位置,两者之间用空格分隔。

注意,在使用schemaLocation属性时,也需要指定该属性来自哪里。

XML的编程

在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。

SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

JAXP的SAX解析

只能做查询,不能做增删改。

SAX解析过程

解析器

获取解析器的工厂

获取解析器对象

解析XML(XML的文件的地址,事件处理器)

事件处理器

自己编写的类,需要继承DefalutHandler类,重写三个方法。

startElement()

characters()

endElement()

SAX的解析原理:

解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。

事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理



JAXP 的SAX解析案例

package cn.itcast.jaxp.sax;

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

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
* SAX的入门
* @author Administrator
*
*/
public class JaxpSaxTest {

public static void main(String[] args) {
try {
run1();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 获取所有的解析的内容
* @throws Exception
* @throws ParserConfigurationException
*/
public static void run1() throws Exception{
// 获取SAX的解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
// 获取解析器
SAXParser parser =  factory.newSAXParser();
// 解析
parser.parse("src/book2.xml", new MyHandler2());
}
}

/**
* 获取作者标签的文本内容
*
*/
class MyHandler2 extends DefaultHandler{
// 如果解析到作者标签的时候,flag设置成true
private boolean flag = false;
private int count = 0;

/**
* 默认解析开始标签,默认调用该方法
*/
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// 如果要是作者标签,flag设置成true
if("作者".equals(qName)){
flag = true;
count++;
}
}

/**
* 能控制characters的输出,我只在解析作者标签的时候,才打印
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
// 如果flag是true,就打印
// 每一次都打印
if(flag && count == 1){
String str = new String(ch,start,length);
System.out.println(str);
}
}

/**
*
*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
// flag恢复成false
flag = false;
}
}

/**
* 自己事件处理器
* 重写三方法
* @author Administrator
*
*/
class MyHandler extends DefaultHandler{

/**
* 只要一解析到开始标签的时候,默认调用该方法,把解析的内容赋值给参数。
*/
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("开始标签:"+qName);
}

/**
* 只要解析到文本的内容,默认调用该方法
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
String str = new String(ch,start,length);
System.out.println(str);
}

/**
* 解析到结束标签的时候,默认调用方法,把解析的内容赋值给参数。
*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("结束标签:"+qName);
}

}


DOM4J的解析

Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。

Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。

使用Dom4j开发,需下载dom4j相应的jar文件。

dom4j-1.6.1.jar
导入到工程中。

WEB项目:复制dom4j-1.6.1.jar到 WebRoot – WEB-INF – lib里面。就ok。

非WEB项目 导入后如果未出现
奶瓶
标志,点中jar包右键选择:Build path –> Add to Build Path。

查找标签文本

想要查找内容,需要一层一层去查找内容,通过根节点去查找字节点,再查找子节点的子节点)

具体实现

创建解析器 new SAXReader()

解析xml read()

获取根节点 getRootElement()

获取所有的指定标签的集合 root.elements(标签名)

返回List集合,可以遍历集合或者getIndex()获取Element对象

获取文本 getText()

添加子节点

在指定的节点中新增节点

具体实现

创建解析器 new SAXReader()

解析xml read()

获取根节点 getRootElement()

获取所有的指定标签的集合 root.elements(标签名)

直接调用addElement()设置子节点

使用setText()设置文本

回写xml文件

在指定位置添加子节点

创建元素标签节点 DocumentHelper.createElement()

设置文本 setText()

获取某个标签下的所有子节点 elements(),返回list集合

通过 list.add(index, element)方法在内存中加入子元素

回写xml文件

修改节点文本和删除节点

修改指定节点的文本内容

找到指定的节点 elements()

修改文本内容 setText()

删除节点

找到要删除的节点

通过父节点调用 remove()方法删除

DOM4J对XPATH的支持

导入包
jaxen-1.1-beta-6.jar


使用方式:

selectNodes("/AAA")
返回集合

selectSingleNode()
一个Node对象

参数就是xpath的语法

/AAA/BBB
获取BBB的节点

//BBB
无论层级关系,找到BBB的节点

*
代表是所有

/AAA/BBB[1]
找到BBB的第一个

/AAA/BBB[last()]
最后一个

@
属性

DOM4J练习

package cn.itcast.dom4j;

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

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
* DOM4J的解析XML
* @author Administrator
*
*/
public class Dom4jTest {

public static void main(String[] args) {
try {
run6();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 对XPATH的支持
* @throws Exception
*/
public static void run6() throws Exception{
// 获取解析器对象
SAXReader reader = new SAXReader();
// 解析XML
Document document = reader.read("src/book2.xml");
// List<Node> list = document.selectNodes("/书架/书/作者");
List<Node> list = document.selectNodes("//作者");
Node author2 = list.get(1);
System.out.println(author2.getText());
}

/**
* 修改文本内容
* @throws Exception
*/
public static void run5() throws Exception{
// 获取解析器对象
SAXReader reader = new SAXReader();
// 解析XML
Document document = reader.read("src/book2.xml");
// 获取根节点
Element root = document.getRootElement();
// 获取狗的节点
Element book2 = (Element) root.elements("书").get(1);
Element dog = book2.element("狗");
dog.setText("小狗");
// 回写
// 回写
OutputFormat format = OutputFormat.createPrettyPrint();
// 回写
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
writer.write(document);
writer.close();
}

/**
* 删除子节点
*  删除第二本书下的猫节点
*/
public static void run4() throws Exception{
// 获取解析器对象
SAXReader reader = new SAXReader();
// 解析XML
Document document = reader.read("src/book2.xml");
// 获取根节点
Element root = document.getRootElement();
// 获取猫
Element book2 = (Element) root.elements("书").get(1);
Element cat = book2.element("猫");
// 通过猫获取猫的父节点
// cat.getParent();
// 通过父节点删除猫
book2.remove(cat);
// 回写
OutputFormat format = OutputFormat.createPrettyPrint();
// 回写
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
writer.write(document);
writer.close();
}

/**
* 在第二本书的作者标签之前添加团购价的标签
* @throws Exception
*/
public static void run3() throws Exception{
// List
// 获取解析器对象
SAXReader reader = new SAXReader();
// 解析XML
Document document = reader.read("src/book2.xml");
// 获取根节点
Element root = document.getRootElement();
// 获取第二本书
Element book2 = (Element) root.elements("书").get(1);
// 获取书下的所有子节点,返回List集合
List<Element> list = book2.elements();
// 创建元素对象   DocumentHelper.createElement("狗")
Element dog = DocumentHelper.createElement("狗");
dog.setText("大狗");
// list.add(index,Element);
list.add(1, dog);

OutputFormat format = OutputFormat.createPrettyPrint();
// 回写
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
writer.write(document);
writer.close();
}

/**
* 在第二本书下添加子节点
*/
public static void run2() throws Exception{
// 获取解析器对象
SAXReader reader = new SAXReader();
// 解析XML,返回Document对象
Document document = reader.read("src/book2.xml");
// 获取根节点
Element root = document.getRootElement();
// 获取第二本书
Element book2 = (Element) root.elements("书").get(1);
// 可以直接在第二本书下添加子节点,设置文本内容
book2.addElement("猫").setText("我是猫");
// 回写

// 创建漂亮的格式
OutputFormat format = OutputFormat.createPrettyPrint();
//OutputFormat format = OutputFormat.createCompactFormat();

// 设置编码
format.setEncoding("UTF-8");

// 回写类
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
// 回写了文档对象
writer.write(document);
// 关闭流
writer.close();
}

/**
* 获取第二本书作者的文本内容
* @throws Exception
*/
public static void run1() throws Exception{
// 获取解析器对象
SAXReader reader = new SAXReader();
// 解析XML,返回Document对象
Document document = reader.read("src/book2.xml");
// 获取根节点(书架标签)
Element root = document.getRootElement();
// 获取书的节点,获取第二本书
List<Element> books = root.elements("书");
Element book2 = books.get(1);
// 获取作者的标签
Element author2 = book2.element("作者");
// 获取文本内容
System.out.println(author2.getText());
}

}


扩展练习

通过XML管理学生的信息
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: