简介
XML 被设计用来传输和存储数据。HTML 被设计用来显示数据。
XML 指可扩展标记语言(eXtensible Markup Language)。
XML 是各种应用程序之间进行数据传输的最常用的工具。
树结构
上图表示下面的 XML 中的一本书:
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
实例中的根元素是 <bookstore>。文档中的所有 <book> 元素都被包含在 <bookstore> 中。
<book> 元素有 4 个子元素:<title>、<author>、<year>、<price>。
语法
XML 声明
XML 声明文件的可选部分,如果存在需要放在文档的第一行,如下所示:
<?xml version="1.0" encoding="utf-8"?>
XML 文档必须有根元素
XML 必须包含根元素,它是所有其他元素的父元素,比如以下实例中 root 就是根元素:
<root>
<child>
<subchild>.....</subchild>
</child>
</root>
XML文档由元素构成,每个元素包括开始标签、结束标签和元素内容。
属性
元素可以包含属性,属性提供有关元素的附加信息,并且属性值必须要加引号
属性位于开始标签中,例如:
<person age="30" gender="male">John Doe</person>
XML 标签
所有的 XML 元素一般都有一个关闭标签,但也允许单标签的使用的。
单标签是指在一个标签中同时包含了开始和结束标签,形式类似于HTML中的空元素标签
XML标签对大小写敏感
实体引用
在 XML 中,一些字符拥有特殊的意义。
如果把字符 "<" 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。
这样会产生 XML 错误:
<message>if salary < 1000 then</message>
为了避免这个错误,请用实体引用来代替 "<" 字符:
<message>if salary < 1000 then</message>
在 XML 中,有 5 个预定义的实体引用:
< | < | less than |
---|---|---|
> | > | greater than |
& | & | ampersand |
' | ' | apostrophe |
" | " | quotation mark |
注释:在 XML 中,只有字符 "<" 和 "&" 确实是非法的。大于号是合法的,但是用实体引用来代替它是一个好习惯。
XML元素
什么是 XML 元素?
XML(Extensible Markup Language)元素是XML文档的主要构建块。一个XML元素由开始标签、结束标签和它们之间的内容组成。例如,在以下的XML片段中,<book\>
和</book>
是开始和结束标签,它们之间的内容是该元素的内容:
<book>
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
</book>
在这个例子中,<book>
元素包含了三个子元素:<title>
, <author>
和<year>
。这些子元素也是XML元素,它们有自己的开始和结束标签,以及它们之间的内容。
XML元素可以包含属性,属性提供了有关元素的额外信息。例如,在下面的XML片段中,<book>
元素有一个名为category
的属性,其值为novel
:
<book category="novel">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
</book>
XML元素必须正确嵌套,这意味着每个开始标签都必须有一个对应的结束标签,并且它们必须以正确的顺序关闭。例如,以下的XML是不正确的,因为<title>
元素没有在<book>
元素内部正确关闭:
<book>
<title>The Great Gatsby
<author>F. Scott Fitzgerald</author>
</title>
<year>1925</year>
</book>
XML属性
XML属性提供了关于元素的额外信息,它们总是在开始标签内定义。属性通常出现为名称/值对的形式,
如:name="value"
。
例如,我们可以为上述<book>
元素添加一个id
属性:
<book id="1">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
</book>
在这个例子中,id
是属性名,"1"
是属性值。请注意,属性值必须总是被引号包围,可以使用双引号(")或单引号(')。
属性提供了一种方式来标记元素,或给元素添加额外的数据。在实际的XML文档中,属性可以用于各种目的,例如,指定元素的类型、分类、状态等信息。
XML验证
拥有正确语法的 XML 被称为"形式良好"的 XML。
通过 DTD 验证的XML是"合法"的 XML。
"形式良好"的 XML 文档拥有正确的语法。在前面的章节描述的语法规则:
- XML 文档必须有一个根元素
- XML元素都必须有一个关闭标签
- XML 标签对大小写敏感
- XML 元素必须被正确的嵌套
- XML 属性值必须加引号
<?xml version="1.0" encoding="ISO-8859-1"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
验证 XML 文档
合法的 XML 文档是"形式良好"的 XML 文档,这也符合文档类型定义(DTD)的规则:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE note SYSTEM "Note.dtd">
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
XML DTD
文档类型定义(DTD)是一种定义XML文档结构的方式。它定义了XML文档中允许哪些元素以及元素的排列顺序,哪些元素是空元素,哪些元素可以包含其他元素,以及哪些元素可以携带哪些属性等信息。
DTD可以在XML文档内部定义(内部DTD),也可以在XML文档外部定义(外部DTD)。如果在XML文档内部定义,DTD位于XML声明之后,DOCTYPE元素之内。如果在XML文档外部定义,需要在DOCTYPE元素中提供一个指向外部DTD文件的URI。
内部DTD的例子:
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
在这个例子中,<!DOCTYPE note [
和]
之间的部分就是DTD。它定义了note
元素必须包含to
,from
,heading
和body
元素,而这些元素都必须包含字符数据(#PCDATA
)。
外部DTD的例子,在DOCTYPE声明中指定一个URI,该URI指向包含DTD的文件。
<!DOCTYPE note SYSTEM "http://127.0.0.1/Note.dtd">
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
在这个例子中,http://127.0.0.1/Note.dtd
是一个外部文件,它包含了DTD的定义。SYSTEM
关键字表示这是一个系统文件。
请注意,使用外部DTD可能会带来一些安全风险,因为它允许从外部源引入代码。因此,在处理包含外部DTD的XML文档时,需要确保你的解析器配置正确,以防止潜在的安全问题。
这只是DTD的基础,DTD还有许多其他的功能,例如定义属性、实体等。
XML Schema
W3C 支持一种基于 XML 的 DTD 代替者,它名为 XML Schema:
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
XML验证器
XML 错误会终止程序
XML 文档中的错误会终止的 XML 应用程序。
W3C 的 XML 规范声明:如果 XML 文档存在错误,那么程序就不应当继续处理这个文档。理由是,XML 软件应当轻巧,快速,具有良好的兼容性。
如果使用 HTML,创建包含大量错误的文档是有可能的(比如忘记了结束标签)。其中一个主要的原因是 HTML 浏览器相当臃肿,兼容性也很差,并且它们有自己的方式来确定当发现错误时文档应该显示为什么样子。
使用 XML 时,这种情况不应当存在。
DTD 验证 XML
根据DTD来验证XML文档是一种常见的做法,其目的是确保XML文档的结构符合预定义的规则。验证过程通常由XML解析器完成,如果XML文档违反了DTD中的规则,解析器会抛出错误。
下面是一个简单的例子,说明如何使用DTD来验证XML文档。
首先,我们有一个简单的DTD文件(假设名为note.dtd
):
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
然后,我们有一个XML文档,它引用了这个DTD文件:
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
当我们解析这个XML文档时,解析器会检查每个元素是否符合DTD中的定义。例如,note
元素必须包含to
,from
,heading
和body
元素,这些元素都必须包含字符数据。如果XML文档违反了这些规则,解析器会抛出错误。
请注意,虽然DTD是XML规范的一部分,但在很多实际应用中,人们更倾向于使用XSD(XML Schema Definition)来定义和验证XML文档的结构,因为XSD比DTD更强大,更灵活。
XSD 验证 XML
XML Schema(XSD)是一种用于描述和验证XML文档结构的语言。和DTD相比,XSD更加强大和灵活,它支持更多的数据类型,并且可以在元素和属性级别上定义更详细的约束。
以下是一个简单的XSD(note.xsd
)示例:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
这个XSD定义了一个note
元素,它包含四个子元素:to
,from
,heading
和body
,所有这些子元素都必须是字符串。
然后,我们可以有一个XML文档(note.xml
):
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
要根据XSD验证这个XML文档,我们需要使用一个支持XSD验证的XML解析器。这通常可以在编程语言(如Java,C#,Python等)的XML处理库中找到。
验证过程通常是:加载XSD,加载XML,然后让解析器检查XML是否符合XSD的规则。
在Python中,可以使用lxml
库来进行XSD验证。以下是一个简单的示例:
from lxml import etree
# 加载XSD
with open('note.xsd', 'r') as f:
schema_root = etree.XML(f.read())
schema = etree.XMLSchema(schema_root)
# 加载XML
with open('note.xml', 'r') as f:
doc = etree.XML(f.read())
# 验证XML
schema.assertValid(doc)
如果XML文档不符合XSD的规则,assertValid
方法会抛出异常。
XMLHttpRequest 对象
XMLHttpRequest是实现Ajax(Asynchronous JavaScript and XML)的关键技术之一
XMLHttpRequest 对象用于在后台与服务器交换数据。XMLHttpRequest 对象是开发者的梦想,因为能够:
- 在不重新加载页面的情况下更新网页
- 在页面已加载后从服务器请求数据
- 在页面已加载后从服务器接收数据
- 在后台向服务器发送数据
Ajax是一种在无需刷新整个页面的情况下,与服务器交换数据并更新部分网页的技术。XMLHttpRequest对象用于在后台与服务器交换数据。
这是一个基本的XMLHttpRequest的使用示例:
var xhr = new XMLHttpRequest();
xhr.open("GET", 'https://api.example.com/data', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200)
console.log(xhr.responseText);
}
xhr.send();
在这个例子中,创建了一个新的XMLHttpRequest对象,然后用open
方法初始化一个GET请求到指定的URL。设置onreadystatechange
属性为一个函数,这个函数会在服务器的响应到达时被调用。
在这个函数中,检查readyState
是否为4(表示请求已完成)和status
是否为200(表示HTTP响应是“OK”),如果是,就打印出服务器的响应文本。最后,浏览器用send
方法发送请求。
调用xhr.send()时,请求会被发送到服务器,然后代码会继续向下执行,而不会等待服务器的响应。这就是为什么它被称为“异步”的原因。
请注意,虽然Ajax的名字中包含“XML”,但实际上你可以使用任何格式的数据,包括JSON,HTML等。在现代Web开发中,JSON是最常用的数据格式。
XML解析器
所有现代浏览器都有内建的 XML 解析器。
XML 解析器把 XML 文档转换为 XML DOM 对象 - 可通过 JavaScript 操作的对象。
跨域访问
出于安全方面的原因,现代的浏览器不允许跨域的访问(但有例外,如CORS)。这意味着,网页以及它试图加载的 XML 文件,都必须位于相同的服务器上。
跨域访问,也称为跨源资源共享(CORS,Cross-Origin Resource Sharing),是一种浏览器使用额外的HTTP头部信息来让一个网页从不同的源(域名、协议或端口)获取权限访问另一个源的选定资源的机制。
为了理解跨域,我们首先需要理解"同源策略"。同源策略是一种安全策略,它限制了从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。如果两个页面的协议、端口(如果指定)和主机都相同,那么我们称这两个页面是同源的。
例如,以下的地址都不与页面 "http://www.example.com/dir/page.html" 同源:
http://api.example.com/dir/page.html (不同的子域)
https://www.example.com/dir/page.html (不同的协议)
http://www.example.com:8080/dir/page.html (不同的端口)
同源策略是为了防止某个恶意网站获取或设置另一个网站的数据。但是,有时我们确实需要进行跨域访问,这就需要使用CORS。
CORS工作原理是,它会在请求头中添加一些信息,告诉服务器请求是来自哪里。服务器可以根据这些信息决定是否允许这个请求。如果服务器允许这个请求,那么它会在响应头中添加一些信息,告诉浏览器可以接收这个跨域的响应。如果服务器不允许这个请求,那么浏览器就会阻止这个响应被接收。
注意,CORS是由服务器来实施的,而不是客户端。也就是说,是否允许跨域访问是由服务器决定的,而不是浏览器。