XML详解–语法、DTD、schema

关于XML语法和 DTD、schema两种约束的一些自己的理解!

概述XML文档结构

  • 每个XML文档都分为两部分:序言(Prolog)和文档元素(或文档节点)
    image

例子:写一段XML然后简单分析一下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myfile [
        <!ELEMENT myfile (title,author)>
        <!ELEMENT title (#PCDATA)>
        <!ELEMENT author (#PCDATA)>
        ]>
<myfile id="11">
    <!--注释信息-->
    <title>XML</title>
    <author>hjk</author>
</myfile>

分析

  • 首先前六行是XML文档的序言,包含了此文档的元数据,就是文档的基本数据

    • 第一行<?xml version="1.0" encoding="UTF-8"?>是XML文档的一个声明,有效的XML文档的第一行必须是XML文档的声明;这个格式是基本固定的前面的标签必须写成<?xml,后面version=是版本号,目前只有两个版本1.0和1.1,encoding是编码格式,不管是version还是encoding等于的内容都必须用单引号或者双引号包含。
    • 第二行内部定义了XML文档的DTD,DTD就是自定义标签之间的关系。<!ELEMENT myfile (title,author)>这个意思是myfile标签包含两个子标签title,author。<!ELEMENT title (#PCDATA)>表示title是一个PCDATA类型,PCDATA(可解析的字符数据)。
  • 第七行到最后就是文档节点

    • <myfile>是根元素,ids是属性,下面是注释,title和author是子元素
  • 上面没有定义处理命令,补充一下:处理指令可以用于将信息传递给应用程序。处理指令可以出现在文档任意位置的标记外部。可以出现在序言中,包括文档的类型定义(DTD),文本内容或者文档之后
    处理指令的语法:

<?target instructions?>
  • 意思
    • target 标识指令指向哪个应用程序。
    • instruction 字符,描述了应用程序要处理的信息

一个常用的处理指令的例子是通知浏览器对XML进行转换,如下所示:

<?xml-stylesheet type="text/xsl" href="appUsers.xslt" ? >

XML语法

XML文档规则

格式良好的XML文档,包含一个或多个元素,并且他们相互之间必须正确的嵌套。必须有且只有一个根元素,包含其他所有的元素。所有元素构成一个简单的层次树,所以元素与元素之间唯一的直接关系就是父子关系。

格式良好的XML文档

格式良好的XML文档不一定是有效的XML文档,有效的XML文档肯定是格式良好的XML文档

  • 必须包含声明语句
<?xml version="1.0" encoding="UTF-8"?>
  • 区分大小写
    标签

    是两个标签,不能进行匹配,,否者报错.建议同意使用大小写
  • 所有XML文档必须有且只有一个根元素
  • 属性值必须使用引号
  • 所有标签必须有相应的结束标签
  • 所有空标签必须被关闭
<title></title>
</title>
  • 标签必须正确嵌套
<title><name>...</name></title>  正确
<title><name>...</title></name>  错误

XML字符引用和实体引用

字符引用

有一些字符键盘上是没有的或者是一些图形字符。所以XML文档可以使用Unicode或者十六进制数字将他们字符引用的形式加入
语句为:

©
©

代码:

<?xml version="1.0" encoding="UTF-8"?>

<data>
    <char>©</char>
    <char>©</char>
</data>

效果:
image

实体引用

实体引用时在一个合法的XML名字前面加上一个&,后面加上一个分号

&name;
实体(这里面最后面应该时英文分号; 用途
&amp; 通常用来代替&
&lt; 通常代替<
&gt; 通常代替>
&apos; 通常代替’
&quot; 通常代替”

自定义实体引用
必须在文档使用前,在DTD文档中进行定义。
自定义实体定义语法:

<!DOCTYPE filename[
<!ENTITF entity-name"entity-content"
]>

例子

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE
        student[
        <!ELEMENT student (name,sex)>
        <!ELEMENT name (#PCDATA)>
        <!ELEMENT sex (#PCDATA)>
        <!ENTITY me "hjk">
        ]>
<student>
    <name>&me;</name>
    <sex>男</sex>
</student>

效果:可以看到

&me;
被赋值为hjk,这是因为上面的DTD定义的原因。
image

命名空间

XML命名空间提供了一种避免命名冲突的方法。
命名冲突,就是两个不同的XML文档使用同一个名字,来描述不同元素的情况。如果这两个XML文档时独立的运行的,那没有影响,但是如果恰巧一起使用,就会出现命名冲突的情况。

命名空间使用

命名空间通过给标识名称加一个网址(URL)以定位的方法来区别这些名称相同的标识。命名空间需要在XML文档开头部分声明,命名空间声明一般放置在元素的开始标记处。
语法格式

xmlns:prefix="URL"

prefix是命名空间的前缀,是可选的。


命名空间两种声明方式
  • 默认声明
<?xml version="1.0" encoding="UTF-8" ?>

<student xmlns="http://www.edu.cn/xxx/xx">
    <name>hjk</name>
    <sex>男</sex>
</student>

我个人理解就是给student加一个唯一的标识,其实这个URL存在正确与否都不重要,只要是唯一的就行,用这个URL来区分这些标签。

  • 明确声明
<?xml version="1.0" encoding="UTF-8" ?>

<h:student xmlns:h="http://www.edu.cn/xxx/xx">
    <h:name>hjk</h:name>
    <h:sex>男</h:sex>
</h:student>

明确声明感觉就像是取一个别名,这个元素的每一个子元素和他本身都需要用这个别名的前缀。

文档内容和模式的定义

文档类型定义-DTD

内部DTD

上面已经提到了,这里简单说一下

<!DOCTYPE myfile [
        <!ELEMENT myfile (title,author)>
        <!ELEMENT title (#PCDATA)>
        <!ELEMENT author (#PCDATA)>
        ]>

外部DTD

外部DTD的好处就是:它可以方便搞笑的被多个XML文档共享
外部DTA的定义和内部差不多,不在需要<!DOCTYPE>,直接写内容就可以,但是要保存成dtd文件,即文件名为name.dtd,name是文件名
外部dtd文件,文件名myfile.dtd

<!ELEMENT myfile(title,author)>
<!ELEMENT title(#PCDATA)>
<!ELEMENT author(#PCDATA)>

那么如何引用呢。引用格式为

<!DOCTYPE type-of-doc SYSTEM/PUBLIC"dtdfile-name">

实例引用上面mufile.dtd文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE myfile SYSTEM "myfile.dtd">
<myfile>
    <title>XML</title>
    <author>hjk</author>
</myfile>

解释说明:

  • !DOCTYPE 指要定义一个DOCTYOE
  • type-of-doc 指文档类型名称,由用户自己定义,通常与使用这个DTD文件XML文档根元素名称一致
  • SYSTEM/PUBLIC 二选一,SYSTEM是指私有的外部DTD文件,就是自己或者合伙人写的。PUBLIC指文档调用一个公用的DTD文件,由一个权威的机构定制的,提供给特定行业或公众的DTD。
  • dtdfile-name;就是存放DTD文件的地址和名称,同目录下只写名称就可以。
实例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE NEWSPAPER[
<!ELEMENT NEWSPAPER (ARTICLE+)>
<!ELEMENT ARTICLE (HEADLINE,BYLINE,LEAD,BODY,NOTES)>
<!ELEMENT HEADLINE (#PCDATA)>
<!ELEMENT BYLINE (#PCDATA)>
<!ELEMENT LEAD (#PCDATA)>
<!ELEMENT BODY (#PCDATA)>
<!ELEMENT NOTES (#PCDATA)>

<!ATTLIST ARTICLE AUTHOR CDATA #REQUIRED>
<!ATTLIST ARTICLE EDITOR CDATA #REQUIRED>
<!ATTLIST ARTICLE DATE CDATA #REQUIRED>
<!ATTLIST ARTICLE EDITION CDATA #REQUIRED>

<!ENTITY NEWSPAPER "Vervet Logic Times">
<!ENTITY PUBLISHER "Vervet Logic Press">
<!ENTITY COPYRIGHT "Copyright 1998 VERVET Logic Press">
]>
<NEWSPAPER>
	<ARTICLE AUTHOR="&NEWSPAPER;" EDITOR="&PUBLISHER;" DATE="&COPYRIGHT;" EDITION="1.0">
		<HEADLINE>我的XML文件</HEADLINE>
		<BYLINE>hjk</BYLINE>
		<LEAD>xiangfeng</LEAD>
		<BODY>woaixml</BODY>
		<NOTES>111</NOTES>
	</ARTICLE>
</NEWSPAPER>

上面是定义一个内部的DTD格式,第三行的<!ELEMENT NEWSPAPER (ARTICLE+)> ARTICLE+这个加号+表示这个标签元素内有属性,属性的定义在第十行是自定义实体。

属性类型意义
类型 含义
CDATA 纯文本,由可显示字符组成的字符串
Enumerated 取值来自一组可接受的取值范围,在()内定义
ID 以属性值的方式为文档中的某个元素定义唯一的标识,用以区分具有相同结构和相同属性的不同元素
IDREF/IDREFS 属性值引用以定义的ID值,方法是把这个元素的ID标识作为该属性的取值。IDREFS是IDREF的复数形式,取值可以是若干个ID值,并把这些ID值用空格隔开。
ENTITY 取值为一个实体
ENTITIES 该属性包含多个外部entity,不同的entity之间用空格隔开
NMTOKEN 表示属性值只能由字母、数字、下划线、.、:、-组成
NMOTOKENS 表示属性值能够由多个NMTOKEN组成,每个NMTOKEN之间用空格隔开
NOTATION 取值为一个DTD中生命的符号,这个类型对于使用非XML格式的数据非常有用
属性特点意义

名称 定义
#REQUIRED 必须赋值的属性,XML文档中必须为这个属性赋予一个属性值
#IMPLIED 属性值可有可无的属性,不要求在XML文档中给该属性赋值,而且也无须再DTD中为该属性提供默认值
#FIXED value 固定取值属性,需要为一个特定的属性提供一个默认值,并且不希望XML文档中另外给出属性值来代替这个默认值
Default value 事先定义了默认值的属性,需要再DTD中提供一个默认值,再XML文档中可以为该属性赋予一个新的属性值,也可以不另外给出属性值,而采用DTD中给出的默认值

image

模式定义-xsd

xsd:XML Schema Definition 缩写.可扩展标记语言架构是以可扩展标记语言(标准通用标记语言的子集)为基础的,它用于可替代文档类型定义(外语缩写:DTD);一份XML schema文件描述了可扩展标记语言文档的结构

XML Schema 相对于DTD的优点

  • 基于XML,没有专门的语法。
  • 可以像其他XML文件一样被解析和处理
  • 支持一系列的数据类型(int、float、boolean、date等)。
  • 可扩充的数据模型
  • 支持综合命名空间
  • 支持属性组

XML Schema文档本身也是XML文档

Schema文档结构

由三部分组成:

  • 命名空间的定义
  • 根元素名字和类型的定义
  • 子元素名字和类型的定义,并说明和根元素的关系!
    示例:
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
</xs:schema>

解释:
第一行和xml文档意思一样。
第二行,所有的Schema文档必须是使用schema元素为根元素,并且xmlns属性指定的是”http://www.w3.org/2001/XMLSchema” 的命名空间!

定义一个xsd文档

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="PRODUCTDATA" type="prdata"/>
    <xs:complexType name="prdata">
        <xs:sequence>
            <xs:element name="PRODUCT" type="prdt"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="prdt">
        <xs:sequence>
            <xs:element name="PRODUCTNAME" type="xs:string"/>
            <xs:element name="DESCRIPTION" type="xs:string"/>
            <xs:element name="PROCE" type="xs:positiveInteger"/>
            <xs:element name="QUANTITY" type="xs:nonNegativeInteger"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

我们知道定义的XML Schema 文档是验证XML的结构的。那么我们先看一下这个xml文档定义的是什么样的结构在解释!

<PRODUCTDATA> <!--产品数据-->
    <PRODUCT> <!--产品-->
        <PROODUCTNAME></PROODUCTNAME> <!--产品名-->
        <DESCRIPTION></DESCRIPTION> <!--产品描述-->
        <PRICE></PRICE> <!--产品价格-->
        <QUANTITY></QUANTITY> <!--产品数量-->
    </PRODUCT>
</PRODUCTDATA>
  • 那么现在再来看这个XML Schema文档就会容易理解一点吧。

  • elementFormDefault和attributeFormDefault是xs的两个元素
  • 在第三行声明根元素PRODUCTDATA,并且类型为prdata,prdata是复杂类型。
  • 第四行是定义一个名为prdata的复杂类型。
  • sequence 元素要求组中的元素以指定的顺序出现在包含元素中。每个子元素可出现 0 次到任意次数
  • 第四到八行就是定义一个复杂类型,这个复杂类型包含一个名叫PRODUCT元素。
  • 同理的可以看到,第九到第十六行定义一个名为prdt的复杂类型,这个类型里面包含了四个简单类型。至于为什么定义这个复杂类型,那是第一个复杂类型里面的元素是我们现在定义的prdt的类型。
    那么现在应该有点晕头转向,多看几遍自己理解理解应该就能明白!

XML Schema的数据类型的声明

简单数据类型的声明

  • Primitive原始数据类型(string、boolean、 decima(十进制数字)、 float、 double、 timeDuration(持续时间)、 dateTime(特定时间)、 time(特定时间,每天重复)、 date(日期)、 anyURL(URL)、 recurring Duration(特定间隔后重现的持续时间) )
  • Derived派生数据类型(integer、 long、 nonNegativeInteger(大于等于0的整数)、 positiveInteger(大于0的整数)、 int、 time(每天时间重现的一个实例,recurringDuration导出的)、 date)
  • 定义简单数据类型
<xs:element name="元素名称" type="数据类型名" default="默认值"/>
自定义简单数据类型
    <xs:simpleType name="自定义数据类型名称">
        <xs:restriction base="所基于的内置数据类型名称">
            <!--自定义数据类型的内容-->
        </xs:restriction>
    </xs:simpleType>


    <!--定义一个电话号码-->
    <xs:simpleType name="phoneno">
        <xs:restriction base="xs:string">
            <!--自定义数据类型的内容-->
            <xs:length value="8"/>
            <xs:pattern value="\d{4}\d{3}"
        </xs:restriction>
    </xs:simpleType>

定义一个简单的数据类型原因:我们有原始数据类型和派生数据类型为什么还要自定义简单的数据类型呢?那是因为这些基础的数据类型并不能满足我们所有的要求,就如上面的定义一个手机号,我们可以定义一个8位的int型数据,但是他可能没有我们定义这种显示的明确,上面定义的格式是“0532-123”!

  • resstriction中可以使用的关键字及其含义
子元素 作用
enumeration 指定的数据集中选择
fractionDigits 限定最大的小数位,用于控制精度
length 指定数据长度
maxExclusive 指定数据的最大值(数据<maxExclusive)
maxInclusive 指定数据的最大值(数据<=maxInclusive)
maxLength 最大长度
minExclusive (数据>minExclusive)
minInclusive (数据>=minInclusive)
minLength 最小长度
Pattern 指定数据规范

复杂数据类型的声明

什么是复杂数据类型?
使用简单的数据类型表示不了的数据结构,简单来说就是含有多个基本数据类型的一个结构,例如:描绘一辆汽车简单的叫汽车并没有一个概念。给它加一些属性就会使描述的很清晰:(速度、长宽、价格等)。然而只描述骑车就可以使用一个简单的string类型描述。但如果我们要描述里面的属性那么我们就需要自己定义复杂的数据类型了。

定义语法

    <xs:complexType name="名称">
        <!--子元素和属性的声明-->
    </xs:complexType>

实例:

    <xs:element name="order" type="address"/>
    <xs:complexType name="address">
        <xs:sequence>
            <xs:element name="stress" type="xs:string"/>
            <xs:element name="city" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>

在第一行我定义了一个名为order的元素类型位address,地址可能会让你写城市、街道等,我们知道基本数据类型里并没有这个元素,所以这么写肯定会报错,如果想要变正确,那就需要我们自己去定义它。下面的代码就是定义一个名为address的数据类型,里面包含两个string类型的元素。


-那这个名为order元素如果不仅有子元素,还有属性怎么定义呢?
属性的定义语法:

        <xs:attribute name="属性名" default="默认值" fixed="固定值" type="数据类型名" use="optional"/>

use:指定属性使可选的还是必须填写的。optional可选的,默认属性。required强制的。


两种引入方式:
attribute必须作为scherma、complexType或者attributeGroup元素的子元素!

  • 第一种
    直接写在<xs:complexType>标签中,和定义子元素位置一致。
  • 第二种
    写在<xs:attributeGroup>标签中,在引入<xs:complexType>
 <xs:attributeGroup name="personattr">
  <xs:attribute name="attr1" type="string"/>
  <xs:attribute name="attr2" type="integer"/>
</xs:attributeGroup>

<xs:complexType name="person">
  <xs:attributeGroup ref="personattr"/>
</xs:complexType>