1.XML和DTD以及Schema
一、XML的简介
XML是指可扩展的标记语言,它是一种标记语言,很类似于HTML。它被设计的宗旨是传输数据,而非显示数据。
XML标签没有被预定义,需要用户自行定义标签。
XML技术是W3C组织发布的,目前遵循的是W3C组织于2000年发布的XML1.0规范。
XML被广泛认为是继Java之后再Internet上最激动人心的新技术。
二、XML技术用于解决什么问题?
在现实生活中存在大量有关系的数据,如下图所示。
问题:这样的数据该如何表示并交给计算机处理呢?
XML语言出现的根本目的在于描述如上图所示那种有关系的数据。
XML是一种通用的数据交换格式。
在XML语言中,它允许用户自定义标签。一个标签用于描述一段数据;一个标签可分为开始标签和结束标签,在起始标签之间,又可以使用其他标签描述其他数据,一次来是你先数据关系的描述。
XML中的数据必须通过软件程序来解析执行或显示,如IE等;这样的继续程序称之为Parser(解析器)。
<?xml version="1.0" encoding="UTF-8"?>
<中国>
<北京>
<海淀></海淀>
<丰台></丰台>
</北京>
<山东>
<济南></济南>
<青岛></青岛>
</山东>
<湖北>
<武汉></武汉>
<荆州></荆州>
</湖北>
</中国>
三、XML常见应用
XML技术除了用于保存有关系的数据之外,它还经常用作软件的配置文件,以描述程序模块之间的关系。
在一个软件系统中,通过XML配置文件可以提高系统的灵活性。即程序的行为是通过XML文件来配置的,而不是硬编码。
数据交换:不同语言之间用来交换数据。
四、XML的语法
一个XML文件分为如下几部分内容:
文档声明
元素
属性
注释
CDATA字节、特殊字符
处理指令(没用)
五、XML语法之文档声明
在编写xml文档的时候,需要先使用文档声明来声明此文件是一个XML文档,并且必须出现在文档的第一行,并且必须指定。
最简单的语法<?xml version="1.0"?>
用encoding属性说明文档所使用的字符编码。保存在磁盘上的文件编码要与声明的编码一致。如:<?xml version="1.0" encoding="utf-8"?>
用standalone属性说明此文档是否独立,即是否依赖其他文档。如:<?xml version="1.0" standalone="yes" ?>,其中yes表示不引用外部的文件,no表示需要引用。(不常用)。
<?xml version="1.0" encoding="UTF-8"?>
<中国>
<北京>
<海淀></海淀>
<丰台></丰台>
</北京>
<山东>
<济南></济南>
<青岛></青岛>
</山东>
<湖北>
<武汉></武汉>
<荆州></荆州>
</湖北>
</中国>
六、xml语法之元素
xml元素指xml文件中出现的标签。一个标签分为起始和结束标签(不能省略)。一个标签有如下几种书写形式
包含标签主体:<tag>content</tag>
不含标签主体:<tag/>
一个标签中可以嵌套若干子标签,但所有标签必须合理的嵌套,不允许有交叉嵌套。
一个xml文档必须有且仅有一个根标签,其他标签都是这个根标签的子标签或后代标签。
对于xml标签中出现的所有空格和换行,xml解析程序都会当做标签内容进行处理。例如:下面两段内容的意义是不一样的。
第一段:
<网址>http://www.baidu.com/</网址>
第二段:
<网址>
http://www.baidu.com/
</网址>
由于在xml中,空格和换行都作为原始内容被处理,所以,在编写xml文件时,使用换行和缩进等方式让源文件中的内容清晰可读的“良好”书写习惯可能要被迫改变。
一个xml元素可以包含字母、数字以及其他一些可见字符,但必须遵守下面的一些规范:
区分大小写。
不能以数字或“-”开头。
不能以xml开头。
不能包含空格。
名称中间不能包含冒号。
七、xml语法之属性
一个元素可以有多个属性,每个属性都有他自己的名称和取值。
属性值一定要用引号(单引号或双引号)引起来。
属性名称的命名规范和元素的命名规范相同。
元素中的属性是不允许重复的。
在xml技术中,标签属性所代表的信息也可以被改成用子元素的形式来描述。
八、xml语法之注释
xml中的注释语法为:<!-- 这是注释 -->
注意注释是不能嵌套的。
九、xml语法之转义字符
对于一些单个字符,若想显示其原始样式,也可以使用转义的形式予以处理。
特殊字符 | 替代符号 |
& | & |
< | < |
> | > |
" | " |
' | ' |
十、xml语法之CDATA区
CDATA区是Character Data的缩写。
作用:把标签当做普通文本内容。
语法:
<![CDATA[内容]]>
十一、xml语法之处理指定(没用)
处理指定,简称PI。
作用:用来指挥软件如何解析xml文档。
语法:必须以“<?”开头,以“?>”结尾。
常用处理指令:
xml声明:
<?xml version="1.0" encoding="utf-8"?>
xml-stylesheet指令:
作用:指示xml文档所使用的css样式xsl。
<?xml-stylesheet type="text/css" href="#css的地址"?>
十二、xml语法规则总结
所有xml元素都必须有关闭标签。
xml标签对大小写敏感。
xml必须正确的嵌套。
xml文档必须有且仅有一个根元素。
xml的属性值必须加引号。
特殊字符必须转义。
xml中的空格、回车换行解析时会被保留。
十三、xml约束之DTD的起源
为什么需要约束??
xml都是用户自定义的标签,如果出现小小的错误,软件程序将不能正确的获取文件中的内容而报错。(如Tomcat等)
xml技术中,可以编写一个文档来约束一个xml的书写规范,这个文档称之为约束。
两个概念:
格式良好的xml: 遵循xml语法的xml。
有效的xml:遵循约束文档的xml。
总之:约束文档定义了在xml中允许出现的元素名称、属性及元素出现的顺序等等。
十四、xml约束概述
什么是xml约束?
在xml技术里面,可以编写一个文档来约束一个xml文档的书写规范,称为xml约束。
常用的约束技术?
xml DTD
xml Schema
十五、DTD快速入门
book.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价,简介)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
<!ELEMENT 简介 (#PCDATA)>
book.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 书架 SYSTEM "book.dtd">
<书架>
<书>
<书名>javaweb开发大全</书名>
<作者>王二</作者>
<售价>79.9</售价>
<简介>这非常不错哦</简介>
</书>
</书架>
快速入门的步骤:
需要出现哪些标签?
在DTD的文件中编写元素
<!ELEMENT 元素名称 元素类型>
判断元素是否是简单还是复杂元素?
如果是简单元素:(#PCDATA) 代表的是字符串
如果是复杂元素:(子节点)
需要在book.xml引入DTD的文件
<!DOCTYPE 根节点 SYSTEM "DTD文件的地址">
十六、DTD与xml文档关联的三种方式
DTD约束即可以作为一个单独的文件编写,也可以在XML文件内编写
使用内部DTD
<!DOCTYPE 根节点 [DTD的代码]>
使用外部DTD
<!DOCTYPE 根节点 SYSTEM "DTD的地址">
使用网络DTD
<!DOCTYPE 根节点 PUBLIC "DTD的名称" "DTD的地址">
十七、DTD之定义元素
在DTD文档中使用ELEMENT关键字来声明一个XML元素。
语法:<!ELEMENT 元素名称 使用规则>
使用规则:
(#PCDATA):指示元素的主体内容只能是普通的文本。
EMPTY:用于指示元素的主体内容为空。比如<br/>
ANY:用于指示元素的主体内容为任意类型。
(子元素):用于指示元素中包含的子元素。
定义子元素及描述它们的关系:
如果子元素用逗号隔开,说明必须按照声明顺序去编写XML文档。
<!ELEMENT FILE (TITLE,AUTHOR,EMAIL)
如果子元素用“|”隔开,则说明任选其一。
<!ELEMENT FILE (TITLE|AUTHOR|EMAIL)
用+、*、?来表示元素出现的次数
如果元素后面没有+、*、?,表示必须且出现一次。
+:表示至少出现一次,一次或多次。
*:表示可有可无,零次、一次或多次。
?:表示可以有也可以无,有的话只能有一次,零次或一次。
十八、DTD之定义属性
属性(ATTLIST)定义
<!ATTLIST 元素名称
属性名 属性类型 约束
属性名 属性类型 约束
……
>
属性声明举例:
<!ATTLIST 商品
类别 CDATA #REQUIRED
颜色 CDATA #IMPLIED
>
对应的xml为:
<商品 类别="服装" 颜色="×××" />
属性值类型:
CDATA:表示属性的取值为普通的文本字符串。
ENUMERATED(DTD没有此关键字):表示枚举,只能从枚举列表中任选其一,如(鸡肉|牛肉|猪肉)。
ID:表示属性的取值不能重复(不能只写数字)。
设置说明:
#REQUIRED:表示该属性必须出现。
#IMPLIED:表示该属性可有可无。
#FIXED:表示该属性的取值为一个固定值。语法::#FILED “固定值”
直接值:表示属性的取值为该默认值。
十九、DTD之定义实体(没用)
实体用于为一段内容创建一个别名,以后在xml文档中就可以使用别名引用这段内容了。
在DTD定义中,一条<!ENTITY 别名 “值”>语句用于定义一个实体。
在元素中引用 &别名;
DTD中定义:
<!ENTITY copyright "版权所有,翻版必究">
xml中引用:
©right;
二十、XML Schema简介
XML Schema也是一种用于定义和描述XML文档结构和内容的模式语言,其出现是为了克服DTD的局限性。
XML Schema是用一套预先规定的XML元素和属性创建的,这些元素和属性定义了XML文档的结构和内容模式。XML Schema规定XML文档实例的结构和每个元素/属性的数据类型。
Schema相对于DTD的明显好处就是,XML Schema文档本身也是XML文档,而不像DTD一样使用自成一体的语法。
二十一、XML Schema的一些概念
XML Schema文件自身就是一个XML文件,但它的扩展名通过为.xsd。
和XML文件一样,一个XML Schema文档也必须有一个根节点,并且这个根节点必须是schema。
应用schema约束 开发xml过程
编写一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI的地址上,这个URI地址叫namespace名称空间,以后XML文件就可以通过这个URI(即名称空间)引用半丁指定名称空间的元素。
二十二、Schema入门
首先在src目录下编写一个book.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<书架>
<书>
<书名>javaweb开发大全</书名>
<作者>王二</作者>
<售价>79.9</售价>
<简介>这非常不错哦</简介>
</书>
</书架>
在src目录下编写一个book.xsd的schema文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
* 引入W3C的名称
* 在根节点上,使用属性xmlns(xml namespace)
* xmlns="http://www.w3.org/2001/XMLSchema"
* 定义元素
* <element name="书架"></element>
* 判断是否是复杂还是简单的元素
* 如果是简单 在element有属性 type="数据的类型"
* 如果是复杂
* 声明标签是复杂的元素 <complexType>
* 子元素之间的关系 <sequence>
* 起名:targetNamespace 目标名称空间(起名)
* 值是任意的:http://www.example.org/book
* elementFormDefault :
* qualified(使用) :质量好的
* unqualified :质量不好的
* 编写属性
* <attribute name="出版社" type="string" use="required" ></attribute>
* name 属性名称
* type 属性类型
* user 属性约束
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/book" 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>
最后在book.xml中修改一下,如下所示
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
* 引入W3C名称空间,我是实例文档。
* xmlns="http://www.w3.org/2001/XMLSchema-instance"
* 引入自己编写的schema的文档
* xmlns="http://www.itcast.cn/1110"
* 问题:元素上不能有相同的属性名称
* 解决:起别名 :aa
* 技巧:在下面出现标签的概率小起别名
* 引入自己编写的schema文档的地址
* schemaLocation属性是W3C提供的,如果W3C名称空间要是有别名的话,先把别名写上。
xsi:schemaLocation="名称空间 schema文件的地址"
-->
<书架 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.example.org/book" xsi:schemaLocation="http://www.example.org/book book.xsd">
<书>
<书名>javaweb开发大全</书名>
<作者>王二</作者>
<售价>79.9</售价>
<简介>这非常不错哦</简介>
</书>
</书架>
二十三、Schema入门总结
2.xml编程
一、xml解析技术概述
XML解析方式分为两种:DOM方式和SAX方式
DOM:文档对象模型(Document Object Model)。这种方式是W3C推荐的处理XML的一种方式。
SAX:Simple API for XML。这种方式不是官方标准,属于开源社区,几乎所有的XML解析器都支持它。
XML解析开发工具包:
JAXP(Java API for XML Processing):是SUN公司推出的解析标准实现。
DOM4j:是开源组织推出的解析开发工具包。(很多公司、框架都使用它)
JDom:是开源组织推出的解析开发工具包。
二、JAXP
JAXP(Java API for XML Processing)开发工具包是JavaSE的一部分,它由以下几个包及其子包组成:
org.w3c.dom:提供DOM方式解析XML的标准接口
org.xml.sax:提供SAX方式解析XML的标准接口
javax.xml:提供了解析XML文档的类
javax.xml.Parsers包中,定义了几个工厂类。我们可以通过调用这些工厂类,得到对XML文档进行解析的DOM和SAX解析器对象。
DocumentBuilderFactory
SAXParserFactory
javax.xml.parsers包中的DocumentBuilderFactory用于创建DOM模式的解析器对象,DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance()方法,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
所以,获得JAXP中的DOM的解析器的步骤如下:
1)调用DocumentBuilderFactory.newInstance()方法得到创建DOM解析器的工厂。
2)调用工厂对象的newDocumentBuilder()方法得到DOM解析器对象。
3)调用DOM解析器对象的parse()方法解析XML文档,得到代表整个文档的Document对象,进而可以利用DOM特性对整个XML文档进行操作了。
DOM编程:
DOM解析器在解析XML文档时候,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。
在DOM中,节点之间关系如下:
位于一个节点之上的节点是该节点的父节点(parent)。
一个节点之下的节点是该节点的子节点(children)。
同一层次,具有相同父节点的节点是兄弟节点(sibing)。
一个节点的下一个层次的节点集合是节点后代(descendant)。
父、祖父节点及所有位于节点上面的,都是该节点的祖先(ancestor)。
Node对象:
Node对象提供了一系列常量来代表节点的类型,当开发人员互殴的某个类型Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。
Node对象提供了相应的方法去获得它的父节点或子节点。编程人员通过这些方法就可以读取整个XML文档的内容,进行增加、修改、删除XML文档的内容了。
示例:DOM解析XML
在src下新建一个book.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<书架>
<书 出版社="机械出版社">
<书名>javaweb开发大全</书名>
<作者>王二</作者>
<售价>79.9</售价>
<简介>这非常不错哦</简介>
</书>
<书 出版社="清华出版社">
<书名>javaSE开发大全</书名>
<作者>李四</作者>
<售价>99.9</售价>
<简介>很好</简介>
</书>
</书架>
在src下新建JAXPDomTest类
package cn.jaxp;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* JAXP的DOM解析XML
*/
public class JAXPDomTest {
public static void main(String[] args) throws Exception {
run();
}
/**
* 获取作者的文本内容
* @throws Exception
*/
public static void run() throws Exception{
//获取解析器工厂类
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//获得解析器对象
DocumentBuilder builder = builderFactory.newDocumentBuilder();
//解析XML的文档,返回Document对象
Document document = builder.parse("src/book.xml");
//获取作者元素的对象集合,返回NodeList
NodeList nodeList = document.getElementsByTagName("作者");
//遍历NodeList集合,拿到每一个作者,打印文本的内容
for(int x =0;x<nodeList.getLength();x++){
Node node = nodeList.item(x);
System.out.println(node.getTextContent());;
}
}
}
示例:修改xml文件
更新xml文档
javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出。
Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:
javax.xml.transform.dom.DomSource类来关联要转换的document对象。
用javax.xml.transform.stream.StreamResult对象来表示数据的目的地。
Transformer对象通过TransformerFactory获得。
修改之前的xml文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?><书架>
<书 出版社="机械出版社">
<书名>javaweb开发大全</书名>
<作者>王二</作者>
<售价>79.9</售价>
<简介>这非常不错哦</简介>
</书>
<书 出版社="清华出版社">
<书名>javaSE开发大全</书名>
<作者>李四</作者>
<售价>99.9</售价>
<简介>很好</简介>
</书>
</书架>
package cn.jaxp;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* JAXP的DOM解析XML
*/
public class JAXPDomTest {
public static void main(String[] args) throws Exception {
/*run();*/
run2();
}
/**
* 获取作者的文本内容
* @throws Exception
*/
public static void run() throws Exception{
//获取解析器工厂类
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//获得解析器对象
DocumentBuilder builder = builderFactory.newDocumentBuilder();
//解析XML的文档,返回Document对象
Document document = builder.parse("src/book.xml");
//获取作者元素的对象集合,返回NodeList
NodeList nodeList = document.getElementsByTagName("作者");
//遍历NodeList集合,拿到每一个作者,打印文本的内容
for(int x =0;x<nodeList.getLength();x++){
Node node = nodeList.item(x);
System.out.println(node.getTextContent());;
}
}
/**
* 在第二本下,载末尾添加子节点
*/
public static void run2() throws Exception{
//获得工厂类
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//获得解析器
DocumentBuilder builder = builderFactory.newDocumentBuilder();
//解析xml,返回Document对象
Document document = builder.parse("src/book.xml");
//获取第二本书
Node book2 = document.getElementsByTagName("书").item(1);
//创建元素对象
Element element = document.createElement("哈哈");
//设置文本内容
element.setTextContent("哈哈还是呵呵");
//把元素对象添加到第二本书下
book2.appendChild(element);
//回写
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/book.xml"));
}
}
修改之后的xml文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?><书架>
<书 出版社="机械出版社">
<书名>javaweb开发大全</书名>
<作者>王二</作者>
<售价>79.9</售价>
<简介>这非常不错哦</简介>
</书>
<书 出版社="清华出版社">
<书名>javaSE开发大全</书名>
<作者>李四</作者>
<售价>99.9</售价>
<简介>很好</简介>
<哈哈>哈哈还是呵呵</哈哈></书>
</书架>
SAX解析
在使用DOM解析XML文档的时候,需要读取整个XML文档,在你内存构成代表整个DOM树的Document的对象,从而再对XML文档进行操作,此种情况下,如果XML文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才能进行操作。
SAX采用事件处理的方式解析XML文件,利用SAX解析XML文档,设计两个部分:解析器和事件处理器。
解析器可以使用JAXP的API创建,创建出SAX解析器后,就 可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档的时候,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松的得到SAX解析器解析到的数据,从而可以决定如何对数据进行处理。
SAX解析原理
SAX是事件驱动的XML处理方法。
它是基于事件驱动的。
startElement()回调在每次SAX解析器遇到元素的起始标记时被调用。
characters()回调为字符数据所调用。
endElement()为元素的结束标记所调用。
DefaultHandler类来实现所有这些回调,并提供所有回调方法默认的空实现。
使用SAX方式解析XML
使用SAXParserFactory创建SAX解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
通过SAX解析工厂得到的解析器对象
SAXParser sp = factory.newSAXParser();
通过解析器对象解析xml文件
sp.parse("book.xml",new XMLContentHandler());
这里的XMLContentHandler()继续DefaultHandler。
package cn.jaxp;
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;
class MyHandler extends DefaultHandler{
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("开始文档:"+qName);
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.println(new String(ch,start,length));
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("结束文档:"+qName);
}
}
public class JAXPSAXTest {
public static void main(String[] args) throws Exception, SAXException {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
saxParser.parse("src/book.xml", new MyHandler());
}
来源:oschina
链接:https://my.oschina.net/u/4310671/blog/4872626