■
第二章 XML
2.1 XML 概述
属性文件是一种单一的平面层次结构,并且要求键值是唯一的。
XML能够表示层次,解决了上述问题。
XML与HTML都是标准通用标记语言(SGML)的衍生
XML和HTML的重要区别:
- XML是大小写敏感的,例如
<H1>
和<h1>
是不同的XML标签 - 在HTML中,如果从上下文可以分清哪里是段落或列表项的结尾,
那么结束标签就可以省略,而在XML中结束标签绝对不能省略。 - 在XML中,只有单个标签而没有相对应的结束标签的元素必须以/结尾,
比如<img src="coffeecup.png"/>
这样,解析器就知道不需要查找</img>
标签 - 在XML中,属性值必须用引号括起来。
- 在HTML中,属性名可以没有值。
文档的结构
●XML文档应当以一个文档头开始
<?xml version="1.0" encoding="UTF-8"?>
因为建立SGML是为了处理真正的文档,因此XML文件叫做文档。
尽管许多XML文件是用来描述通常不称作文档的数据集的。
●文档头之后通常是文档类型定义(Document Type Definition,DTD)
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
文档类型定义的是确保文档正确的一个重要机制,但同文档头一样也不是必需的。
●XML文档正文包含根元素,根元素包含其他元素
元素可以有子元素或者文本。设计时应该避免混合式内容
<font>
Helvetica
<size>36</size>
</font>
●XML文档包含属性,属性只应该用来修改值得解释,而不是用来指定值。
在HTML中属性的使用规则很简单:凡是不显示在网页上的都是属性。
一些标记:
- 字符引用(&#十进制值,进制值)
é,é - 实体引用(&name)
<;>;&;";&apos; - CDATA部分,用
<![CDATA[]]>
来界定其界限,是字符数据的一种特殊形式。
可以用来显示包括<,>,&
之类的字符的字符串
<![CDATA[<&> are my favorite delimiters]]>
不能包含字符串]] - 处理指令(processing instruction)用
<?和?>
来限定其界限。
<?xml-stylesheet href="mystyle.css" type="text/css"?>
- 注释(comment)用
<!--和-->
来限定其界限。
不能包含字符串 --,也绝不应该包含隐藏的命令。
2.2 解析XML文档
用解析器解析XML文档。
- 读入一个文件
- 确认这个文件具有正确的格式
- 将其分携程各种元素。
- 提供访问这些程序的接口
两种解析器:
- 树形解析器,将读入的XML文档转换成树结构。
例如:文档对象模型(Document Object Model, DOM)解析器,
实现简单,但生成的树结构将会消耗大量内存。 - 流机制解析器,在读入XML文档时生成相应的事件。
像XML简单API(Simple API for XML, SAX)解析器
不关心上下文←这句话怎额理解
DOM解析器的接口已经标准化了,Apache Organization和IBM都编写了这些接口的解析器。
JavaXML处理API(Java API for XML Processing,JAXP)库
使得实际上可以以插件形式使用这些解析器中的任意一个。
另外JDK中也包含了一个自己的DOM解析器
注意:如果使用输入流作为输入源,那么对于那些以本文档的位置作为相对路径而被引用的文档,
解析器将无法定位,比如在同一目录中的DTD。但是可以通过安装一个“实体解析器”来解决问题。
<font> <name>Helvetica</name> <size>36</size> </font> NodeList children = root.getChildNodes(); for (int i=0;i<children.getLength();i++) { Node Child = children.iten(i); }
预期取回来两个子元素,但解析器报告却说有5个,另外3个分别为,
<font>和<name>
,</name>和<size>
,</size>和</font>
之间的空白。
如果只希望得到子元素,则可以忽略空白。
NodeList children = root.getChildNodes(); for (int i=0;i<children.getLength();i++) { Node Child = children.iten(i); if (child instanceof Element){ Element childElement = (Element) child; ... } }
如果文档有DTD就可以做的更好。解析器知道哪些元素没有文本节点的子元素,
而且会帮你剔除空白字符。
NodeList children = root.getChildNodes(); for (int i=0;i<children.getLength();i++) { Node Child = children.iten(i); if (child instanceof Element){ Element childElement = (Element) child; Text textNode = (Text)childElement.getFirstChild(); String text = textNode.getData().trim(); if (childElement.getTagName().equals("name")){ name = text; } if (childElement.getTagName().equals("size")){ name = Integer.parseInt(text); } } }
对getData返回值调用trim是个好主意,因为标签在不同行的时候,换行符和空格都在文本里。
对第二层元素,如果要遍历,同样还得用NodeList来循环,
上例因为知道下面已经没有子元素了。所以直接用FirstChild方法取得内容。
如果要枚举节点的属性,可以调用getAttributes方法,它返回一个NameNodeMap对象。
同样遍历NamedNodeMap来遍历子节点,通过getNodeName和getNodeValue来获取属性名和值
NameNodeMap attributes = element.getAttributes(); for(int i=0; i< attributes.getLength(); i++){ Node attribute = attributes.item(); String name = attribute.getNodeName(); String value = attribute.getNodeValue(); } //如果知道属性名,想取属性值 element.getAttribute("unit");
2.3 验证XML文档
上面是通过程序,验证文档的结构,以及进行错误的检查,程序非常冗长。
XML解析器可以自动校验某个文档是否具有正确的结构。
指定文档结构,提供一个文档类型定义(DTD)或一个XML Schema定义。 其包含了用于解释文档应如何构成的规则,这些规则指定了每个元素的合法子元素和属性。
例:DTD含有一个规则,font元素必须总是有两个子元素,name和size
<!ELEMENT font(name,size)>
同样的XML Schema约束表示如下:
<xsd:element name = "font"> <xsd:sequence> <xsd:element name = "name" type = "xsd:string"/> <xsd:element name = "font" type = "xsd:int"/> </xsd:sequence> </xsd:element>
与DTD相比,XML Schema可以表达更加复杂的验证条件。
与DTD语法不同,Schema使用XML,这为处理Schema文件带来了方便。
XML Schema虽然被设计替代DTD,但比较复杂,所以现在还没有得到普遍采纳。
2.3.1 文档定义类型
提供DTD的方式有多种。可以像下面这样将其纳入XML文档中。
<?xml version="1.0"?> <!DOCTYPE configuration [ <!ELEMENT configuration ... > more rules ... ]> <configuration> ... </configuration>
规则被纳入到了DOCTYPE声明中,代码块使用了[]来限定其界限。
文档类型必须匹配根元素的名字
<!DOCTYPE configuration SYSTEM "config.dtd"> <!DOCTYPE configuration SYSTEM "http://myserver.com/config.dtd">
这里的SYSTEM 有什么作用?
如果使用的DTD是相对Url,name要给解析器一个File或者URL对象,而不是InputStream。
如果必须从一个输入流来解释,需要一个实体解析器
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems,Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
如果XML处理器知道如何定位带有公共标识符的DTD,那么就不需要URL了。
指定描述合法的元素属性的规则。通用语法:
<!ATTLIST element attribute type default>
例如:
<!ATTLIST font style (plain|bold|italic|bold-italic) "plain">
<!ATTLIST size unit CDATA #IMPLIED>
2.3.2 XML Schema
如果要在文档中引用Schema文件,需要在根元素中添加属性,
例如
<?xml version ="1.0"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsl:noNamespaceSchemaLocation="config.xsd"> ... </configuration>
这个声明说明Schema文件config.xsd会被用来验证文档。
如果使用命名空间,语法就更加复杂了。详细请参见XML Schema指南
前缀xsi是一个命名空间别名(namespace alias)