XML(eXtensible Markup Language)是
万维网联盟(World Wide Web Consortium W3C)定义的一种
可扩展标志语言。
可扩展性指允许
用户按照XML规
则自定义标记(tags
标签)。
强项:轻松表达多层结构的数据;可扩展。
优点:平台无关,语言无关。设计目标是描述数据并集中于数据的
内容,与
显示分离。
提醒:不能用XML来直接写网页。即便是包含了XML数据,依然要转换成HTML格式才能在浏览器上
显示。
语法规则:
XML
文件有且仅有一个根
标记,其他
标记必须封装在根
标记中,
文件的
标记必须形成树状结构。
大小写敏感。
标记的
属性必须用""或''括起来。
XML细节:
一、 声明
大多数XML文档以XML声明作为开始,它向解析器提供了关于文档的基本信息。
建议使用XML声明,但它不是必需的。如果有的话,那么它一定是文档的第一行
内容。
如:<?xml version="1.0" encoding="UTF-8" standalone="no"?>
声明最多可以包含三个
名称-值对(许多人称它们为
属性,尽管在技术上它们并不是)。
<?xml 问号与xml之间不能有空格。
1)version 是使用的XML 版本:1.0,1.1
2)encoding 是该文档所使用的字符集。该声明中引用的ISO-8859-1 字符集
包括大多数西欧语言用到的所有字符。
默认字符在UTF-8字符集中,这是一个几乎
支持世界上所有语言的字符和象形
文字的Unicode 标准。
3)standalone(可以是yes 或no)定义了是否孤立处理该文档。
如果XML文档没有引用任何其它
文件,则可以指定 standalone="yes"。
如果XML文档引用其它描述该文档可以包含什么的
文件(如DTD),则 standalone="no"。默认值为"no"
二、
标记
左尖括号“<“和右尖括号“>“之间的文本
1. 在< >中的称为开始
标记;在</ >中的称为结束
标记
2. 空
标记:不包含元素的
标记。空
标签必须以“/>”结束。格式: <空
标记的
名称/> <空
标记的
名称 属性列表/>
注意:
除空
标记外,
标签必须成对:有始有终。所有的开始
标签和结束
标签必须匹配。
在
标记符“<“和"
标记的
名称"之间不能含有空格。在
标记符"/>"前面可以有空格或回行。
标签必须嵌套正确。
XML标记必须遵循下面的命名规则:
1.名字中可以包含字母、数字以及其它字母或
文字;还可包含下划线(_)、点(.)、连字符(-)
2.名字不能以数字开头;可以用字母、
文字或者下划线开头。
3.名字不能以字母xml (或XML 或Xml ..) 开头;
4.名字中不能包含空格。
三、 元素
位于开始
标记与结束
标记间
一份文档有且只有一个根元素。
根元素下的所有元素叫“子元素”。
标签必须嵌套正确。
不包含自子元素的元素叫“叶子”;包含子元素的元素叫“分支”。
如: <eric>…… </eric>
四、 属性
一个元素的开始标志中的
名称-值对
所有的
属性值必须位于单引号或双引号中。
每一个元素的
属性不允许出现超过一次。
开始标志内,类似赋值语句
如:<eric age="80">……</eric>
五、 注释
注释可以出现在文档的任何位置。(但不建议放在声明前面,部分浏览器会报错)
注释以 <!-- 开始,以 --> 结束。
注释内不能包含双连字符(--);除此之外,注释可以包含任何
内容。
注释内的任何
标记都被忽略
六、 处理指令
处理指令是为使用一段特殊
代码而设计的
标记,简称为PI。
大多数XML 文档都是以XML 声明开始,该声明本身就是特殊的处理指令。
处理指令对应用程序特定的数据进行编码。一条处理指令包含一个目标,后跟数据。用<?和?>定界符将处理指令包起来。
目标确定应用程序,而对应用程序不能识别的目标,其会忽略这些处理指令。
七、 实体
XML 规范预定义了五个实体。
< ==== <
> ==== >
" ==== ”
' ==== ‘
& ==== &
自定义实体:在DTD中定义 <!ENTITY 实体标志 "实体
内容">
在xml中引用
自定义实体,用 &实体标志; 代表实体
内容。
另外,无法从
键盘输入的字符可以使用字符引用,就是用字符的Unicode
代码点来引用该字符。
以"&#x"开始字符引用,以分号结尾,x必须为小写,使用十六进制。如: = 表示等于号。
也可以使用字符引用来引用 <,>,',",& "
查看字符的
代码点(附件-> 系统工具-> 字符映射表)。
八、 CDATA
当一段文本中出现很多实体引用和字符引用时,会导致文本数据的读写困难,CDATA段就是为了
解决这一问题引入的。
DATA区段开始于 "<![CDATA[" 结束于 "]]>"
CDATA内部的所有东西都会被解析器忽略解析,不用检查它的格式。
但是CDATA段中不能嵌套另一个CDATA段。
九、 属性
属性是
标记的
属性,可以为
标记添加附加信息。
(1)
属性的组成
属性是一个名值对,必须由
名称和值组成,
属性必须在
标记的开始
标记或空
标记中声明,用"="为
属性指定一个值。
语法如下:
<
标记名称 属性列表/>
<
标记名称 属性列表>XXX</
标记名称>
例如: <桌子 width="40" height='100'/>
(2)使有
属性的原则
属性不体现数据的结构,只是数据的附加信息;
一个信息是作为一个
标记的
属性或子
标记,取决于具体问题,不要因为
属性的频繁使用破坏XML的数据结构。
下面是一个结构清晰的XML
文件:
<楼房 height="23m" width="12m">
<结构>混凝土</结构>
<类别>商用</类别>
</楼房>
下面是一个结构不清晰的XML
文件:
<楼房 height="23m" width="12m" 结构="混凝土" 建筑商="华海集团" 类别="商用"></楼房>
十、 名称空间/包
XML
文件允许
自定义标记,所以可能出现同名字的
标记,为了区分这些
标记,就需要使用
名称空间。
名称空间的目的是有效的区分相同的
标记,其实并不真实存在。
语法: 声明有前缀的
名称空间 xmlns:前缀名=
名称空间的名字
声明无前缀的
名称空间 xmlns=
名称空间的名字 (缺省)
注意:当且仅当它们的名字相同时称二个
名称空间相同,也就是说,对于有前缀的
名称空间,如果二个
名称空间的名字相同,即使前缀不相同,也是相同的
名称空间,返之同然。前缀只是方便引用而已。
基本术语
一、序言Prolog:
包括XML声明(XML Declaration)和文档类型声明(Document Type Declaration)。
二、良构(well-formed 规范的):符合W3C定义的XML文档。
验证
为什么需要验证?
对XML
文件施加额外的约束,以便交流。
一、DTD验证
文档类型定义(Document Type Definition)
DTD定义了XML文档
内容的结构,保证XML以一致的格式存储数据。精确的定义词汇表,对XML的
内容施加约束。
符合DTD的规范XML文档称为有效的文档。由DTD定义的词汇表以及文档语法,XML解析器可以检查XML文档
内容的有效性。
规范的XML
文件不一定是有效的;有效的一定是规范的。
1、 DTD声明
1) DTD声明可以在单独的一个
文件中
2) DTD声明可以内嵌在XML
文件中
3) DTD声明可以一部分在单独的
文件中,另一部分内嵌在XML
文件中
2、 引入外部DTD文件
<!DOCTYPE data SYSTEM "Client.dtd">
Data:根节点
名称
Client.dtd:dtd
文件路径
3、 DTD四种标记声明
元素(ELEMENT)、
属性(ATTLIST)、实体(ENTITY)、符号(NOTATION)
1) 元素(ELEMENT) XML元素类型声明
声明元素: <!ELEMENT elementName (contentModel)>
元素的
内容通过
内容模式来描述。
DTD
内容模式的种类有:
EMPTY 元素不能包含任何数据,但可以有
属性(前提是必须声明其
属性)。
不能有子元素。不能有文本数据(
包括空白,换行符)。
DTD中定义: <!ELEMENT elementName EMPTY>
XML中:<elementName/>(推荐) 或者:<elementName></elementName>
(#PCDATA) 规定元素只包含已析的字符数据,而不包含任何类型的子元素的
内容类型。
DTD中定义: <!ELEMENT student (#PCDATA)>
XML中合法
内容: <student>watching TV</student>
(Elements) 元素由
内容模式部件指定。
<!ELEMENT name (child particles) >
内容模式部件可以是下表列出的
内容。
<!ELEMENT name (a,b)> 子元素a、b必须出现,且按照列表的顺序
<!ELEMENT name (a|b)> 选择;子元素a、b只能出现一个
<!ELEMENT name (a) > 子元素a只能且必须出现一次
<!ELEMENT name (a)+ > 子元素a出现一次或多次
<!ELEMENT name (a)* > 子元素a出现任意次(
包括零次、一次及多次)
<!ELEMENT name (a)? > 子元素a出现一次或不出现
Mixed 混合模式:子元素中既可有文本数据又可有下级子元素。
<!ELEMENT rn (#PCDATA| an | en)*>“|”和“*”必须写。
上句表示在 rn 内,字符数据 或 en及an 可以出现任意多次,顺序不限。
优先写(#PCDATA) 如:(#PCDATA|name)* 正确 (name|#PCDATA)*
错误
ANY 元素可以包含任何类型的数据。子元素(必须在DTD中有定义) 和 文本数据(
包括空白)。
DTD中定义: <!ELEMENT a ANY> <!ELEMENT b ANY>
XML中合法
内容: <a>somngthing</a> 或者 <a/> 或者 <a><b>oo</b></a>
2) 属性(ATTLIST) 特定元素类型可设置的属性&属性的允许值声明
<!ATTLIST elementName
attributeName1 attributeType attributeDefault
.......
attributeNameN attributeType attributeDefault>
属性类型 (Attribute Type):
CDATA该
属性只能包含字符数据(注意与CDATA段、PCDATA的区别)
NMTOKEN 是CDATA的子集,它的字符只能是字母,数字,句点,破折号,下划线或冒号。
NMTOKENS 类似NMTOKEN,但这个可以包含多个值,每个值之间用空格隔开。
ID 该
属性的取值在同一文档内是唯一的。一个元素只能有一个ID类型的
属性。
IDREF 类似指针,指向文档中其他地方声明的ID值。如果该
属性取值和指向的ID值不匹配,则返回
错误。
IDREFS 类似IDREF,但它可以具有由空格分隔开的多个引用。
ENTITY 该
属性的值必须对应一个在文档内部声明的但还没有分析过的实体。
ENTITYS 类似ENTITY,但它可以包含由空格分隔开的多个实体。
NOTATION 该
属性的值必须引用在文档中其他地方声明的某个注释的
名称。
(enumerated) 类似枚举的变量,该
属性必须匹配所列的值。各值用“|”分隔开。
如: (春|夏|秋|冬) 实际
内容文档只能从中取一个。
属性特性 (Attribute Default) :
#
required 必须有且只能有一个
属性。
#IMPLIED 可有可无。
#FIXED 在DTD中定义默认值,XML中可以不指定,指定则必须等于该默认值。
attribute-value 如果不指定则用DTD定义的默认值,指定则用指定的值。
<![CDATA[############
属性(ATTLIST)的举例 ############## ]]>
例一(#
required)
DTD中: <!ELEMENT el (#PCDATA)> <!ATTLIST el at1 NMTOKENS #
required at2 CDATA #
required>
XML中,正确: <el at1 = "10 20" at2="10" >something</el>
XML中,
错误: <el at="10">something</el> (没有写另一个#
required的
属性 at2 )
例二(#IMPLIED,#FIXED)
DTD中: <!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA #FIXED "10" at2 CDATA #IMPLIED >
XML中,正确: <el at2="20" >something</el> (at有默认值"10",at2 可写可不写)
XML中,
错误: <el at="11" >something</el>(at要么不写,要写只能写成跟默认值相同的)
例三(attribute-value)
DTD中:<!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA "10" at2 CDATA "20" >
XML中,正确: <el at="11" >something</el>
例四(enumerated + attribute-value)
DTD中:<!ELEMENT el (#PCDATA)> <!ATTLIST el at (10|20|30) "10">
XML中,正确: <el at="20">something</el> (at要么不写,默认值 10;要么在(10|20|30)中选一个写)
<![CDATA[############
属性(ATTLIST)举例 完毕 ############## ]]>
3) 实体(ENTITY) 可重用的内容声明
在DTD中定义 <!ENTITY 实体标志 "实体内容">
在xml中引用
自定义的实体,用 &实体标志; 代表实体
内容。
4) 符号(NOTATION) 不要解析的外部
内容的格式声明。
3、 内部实体:在xml文件里面写(少用)
外部实体:另外在xml同一文件夹下建立一个dtd文件(提倡)
<!--**************** 内外部的实体举例 ***************** -->
外部的:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE root SYSTEM "goodsInfo.dtd"><!--用这句引用外部dtd-->
<root><goodsInfo>
<goodsName>goodsName</goodsName>
<goodsPrice>goodsPrice</goodsPrice>
</goodsInfo></root>
以下是名为"goodsInfo.dtd"
文件
<!ELEMENT root (goodsInfo)>
<!ELEMENT goodsInfo (goodsName,goodsPrice)>
<!ELEMENT goodsName (#PCDATA)>
<!ELEMENT goodsPrice (#PCDATA)>
内部的:
<?xml version="1.0"?>
<!DOCTYPE root [
<!ELEMENT root(student)>
<!ELEMENT student (#PCDATA)>
<!ENTITY CCTV "中央电视台">
]> <!--把DTD
文件写在体内-->
<root><student>
student watch &CCTV;<!--使用
自定义实体 CCTV-->
</student></root>
<!--***************** 内外部的实体举例 完毕 ********************** -->
XML处理模式
一、 DOM 文档对象模式
1.DOM特点:
以树型结构访问XML文档。 一棵DOM树包含全部元素节点和文本节点。可以前后遍历树中的每一个节点。
整个文档树在内存中,便于操作;
支持删除、
修改、重新排列等多种
功能。
将整个文档调入内存(
包括无用的节点),浪费时间和空间。
一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、
cpu)情况下使用。
2.DOM树与节点
XML文档被解析成树型结构。
树由节点组成。共有12种不同的节点。
节点可以包含其他节点(依赖于节点的类型)。
父节点包含子节点。叶子节点没有子节点。
3.节点类型
Document node 包含:一个根Element节点。一个或多个处理指令节点。
Document Fragment node
Element node包含:其他Element节点。若干个Text节点。若干个Attribute节点。
Attribute node 包含:一个Text节点。
Text node
Comment node
Processing instruction node
Document type node
Entity node
Entity reference node
CDATA section node
Notation node
二、 SAX 基于事件处理模式
解析器向一个事件处理程序发送事件,比如元素开始和元素结束,而事件处理器则处理该信息。
然后应用程序本身就能够处理该数据。原始的文档仍然保留完好无损。
<![CDATA[################## SAX处理器(遍历XML) ###########################]]>
import java.io.IOException;
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.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class TestSAXParser {
/** 基于SAX方式解析XML文档 */
public static void main(String[] args)
throws SAXException,ParserConfigurationException,IOException{
SAXParserFactory factory = SAXParserFactory.newInstance(); //创建SAX解析器工厂
factory.setValidating(true); //让error
方法生效
SAXParser parser = factory.newSAXParser(); //
生成一个具体的SAX解析器
parser.parse("src/file/student.xml",new XMLreader()); //开始解析
}}
class XMLreader extends DefaultHandler {
// 只需覆盖我们感兴趣的
方法
private int counter = 0;// 定义一个计数器,保存XML文档触发事件的
次数
@Override // 文档开始事件触发
public void startDocument() throws SAXException {
counter++;
System.out.println(counter + ".解析XML
文件开始...");}
@Override // 文档结束事件触发
public void endDocument() throws SAXException {
counter++;
System.out.println("\r\n"+counter + ".解析XML
文件结束...");}
@Override // 元素开始事件触发
public void startElement(String uri,String localName,String qName,
Attributes atts) throws SAXException {
counter++;
System.out.print(counter+".<"+qName);
for(int i=0; i<atts.getLength();i++){ //读取标志的所有
属性
System.out.print(" "+atts.getLocalName(i)+"="+atts.getValue(i));
}System.out.print(">"); }
@Override // 元素结束事件触发
public void endElement(String uri,String qName) throws SAXException {
counter++;
System.out.print(counter +".</"+qName+">");}
@Override // 文本事件触发 打印时尽量不要换行,否则很难看
public void characters(char[] ch,int start,int length)throws SAXException {
counter++;
String text = new String(ch,start,length); // 当前元素的文本值
System.out.print(counter + ".Text=" + text);}
@Override //这是可恢复
错误。需在SAXParserFactory设置有效性
错误才能生效
public void error(SAXParseException e) throws SAXException {
System.out.println("xml文档有效性
错误:"+e);}
@Override //严重
错误
public void fatalError(SAXParseException e) throws SAXException {
System.out.println("xml文档严重的有效性
错误:"+e);}
}
<![CDATA[################## SAX处理器(遍历XML)结束 ###########################]]>
三、 DOM
<![CDATA[######################### DOM遍历方式 ###########################]]>
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**基于DOM的解析XML文档*/
public class TestDOMParser {
public static void main(String[] args)
throws ParserConfigurationException,SAXException,IOException{
//创建一个DOM解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//从工厂中
生成一个DOM解析器; throws ParserConfigurationException
DocumentBuilder builder = factory.newDocumentBuilder();
//绑定需要解析的XML
文件
File xmlFile = new File("src/file/student.xml");//相对地址,相对于这个工程
//开始解析 ;throws SAXException,IOException
Document document = builder.parse(xmlFile);
//取出唯一的根元素
Element rootElement = document.getDocumentElement();
//
调用业务
方法: 遍历根元素
printElement(rootElement);
}
/** 遍历元素,包含: 子元素、
属性、文本
内容 */
private static void printElement(Element e){
//打印出元素的
标签名
System.out.print("<"+e.getTagName());
//
获取开始
标签的
属性
NamedNodeMap attMap = e.getAttributes();
//循环遍历所有的
属性
for (int i=0;i<attMap.getLength();i++){
Attr attr = (Attr)attMap.item(i);
System.out.print(" "+attr.getName()+"="+attr.getValue());}
System.out.print(">");
//
获取当前元素的所有子节点
NodeList nl = e.getChildNodes();
for (int j=0;j<nl.getLength();j++){
Node n = nl.item(j);
if (Node.ELEMENT_NODE==n.getNodeType()){
printElement((Element)n);//递归
调用,以遍历下一个元素
} else {
System.out.print(n.getTextContent());
}
}
//打印结束
标签
System.out.print("</"+e.getTagName()+">");
}}
<![CDATA[ ###################### DOM遍历 完毕 ##########################]]>
比较
DOM
与
SAX
:
DOM:处理大型
文件时其
性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析
文件之前把整个文档装入内存,适合对XML的
随机访问
优点:1.提供
随机定义元素操作,来回移动指针
2.将整个XML
文件一次性加载到内存,形成虚的内存树
缺点:1.如果XML
文件较大,内存空间占用较大
2.强制将较大的XML
文件加载到内存中,有可能损害
文件
3.
功能通用性
SAX:不同于DOM,SAX是事件驱动型的XML解析方式。它顺序逐行读取XML
文件,不需要一次全部装载整个
文件。当遇到像
文件开头,文档结束,或者
标签开头与
标签结束时,它会触发一个事件,
用户通过在其回调事件中写入处理
代码来处理XML
文件,适合对XML的顺序访问