XML
一、XML
XML document 描述了 structure and data.
- has internal representation of a tree: DOM tree or infoset
- is divided into smaller pieces called elements
1. 基本原則
XML 有着嚴格的錯誤處理(XML has draconian error handling )
- 接受時嚴格
- 發送時嚴格
Postel’s Law: 發送時要保守;接收時要開放. 即: XML 僅滿足Postel’s Law第一條
2. 基本語法
基本結構
第一行是XML聲明,定義XML的版本和使用的編碼
<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
...
</root>
a. 規則
-
所有元素都須擁有關閉標籤:
<p>This is a paragraph</p>
-
XML標籤對大小寫敏感:
<message> 這是正確的 </message>
-
XML必須正確的嵌套:
<b><i> Hello </i><b>
-
XML文檔必須擁有一個根元素(有且僅有一個):
<root> </root>
-
XML的屬性值需加引號:
<node date="08/08/2020"> </node>
-
XML可以使用空元素:
<myname/>
b. 元素 和 屬性
<node date="08/08/2019"> <!-- 屬性 -->
<day>08</day> <!-- 元素 -->
<month>08</month>
<year>2019</year>
</node>
因爲屬性引起的一些問題:
- 屬性無法包含多重的值
<!-- 錯誤,不可重複key-->
<a type="red" type="red"></a>
- 屬性無法描述樹結構
- 屬性不易擴展
- 屬性難以閱讀和維護
使用元素來描述數據,屬性提供與數據無關的信息
c. namespace
XML 命名空間提供避免元素命名衝突的方法: <h:table> </h:table>
# 我們可以在一個文檔中定義多個命名空間
<b:book xmlns:b="http://www.atguigu.com/xml/b" xmlns:a="http://www.atguigu.com/xml/a">
# 可以聲明一個默認的命名空間, 但是要注意的是一個文檔中只能有一個默認的命名空間
<book xmlns="http://www.atguigu.com/xml/b" xmlns:a="http://www.atguigu.com/xml/a">
# 屬性定義的命名空間優先級高於標籤, 即table的命名空間爲foo2
<root xmlns:b="bar" xmlns:f="foo" xmlns="bar">
<f:table xmlns:f="foo2">
<b:tr>
<td>Apples</td>
<td>Bananas</td>
</b:tr>
</f:table>
</root>
3. DOM
XML DOM是用於獲取、更改、添加和刪除XML元素的標準。
a. XML DOM 節點樹
DOM 將 XML 文檔作爲一個樹形結構,而樹葉被定義爲節點。節點樹中的節點彼此之間都有等級關係
<?xml version="1.0" encoding="UTF-8"?>
<mytext content="medium">
<title>Hallo!</title>
<content>Bye!</content>
</mytext>
b. Python 操作DOM實例
參考文檔: XML DOM 獲取節點值
加載並解析XML文件
import xml.dom.minidom
import sys
filename_xml = sys.argv[1]
# dom: 由解析器創建的 XML 文檔
dom = xml.dom.minidom.parse(filename_xml)
獲取元素值
# getElementsByTagName()方法返回包含擁有指定標籤名的所有元素的節點列表,
# 其中的元素的順序是它們在源文檔中出現的順序。
mytextNodes = dom.getElementsByTagName("mytext")
for textNode in mytextNodes:
titleNode = textNode.childNodes[1]
# childNodes[0]: 元素的第一個子元素, 文本節點
titleNodeText = titleNode.childNodes[0]
# nodeValue: 文本節點的值
print(titleNodeText.nodeValue) # Hallo!
獲取屬性值
mytextNodes[0].getAttribute("content");
二、XML Schema
1. RelaxNG
<?xml version="1.0" encoding="UTF-8"?>
<people>
<person age="41">
<name>
<first>Harry</first>
<last>Potter</last>
</name>
<address>4 Main Road </address>
<project type="epsrc" id="1">DeCompO </project>
<project type="eu" id="3"> TONES </project>
</person>
<person>
....
</people>
a. 緊湊語法(compact syntax)
參考文檔:RELAX NG Compact Syntax Tutorial
grammar {
start = people-element
people-element = element people {
person-element+
}
person-element = element person {
attribute age { text },
// 無符號: require
name-element,
// +: 出現1次或1次以上
address-element+,
// *: 出現0次或0次以上
project-element*
}
...
}
數據類型:
text
xsd:integer
xsd:date
b. XML語法(XML syntax)
參考文檔: 官方文檔
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/ structure/1.0">
<start>
<ref name="name-element"> </ref>
</start>
<define name="people-element">
<element name="people">
<oneOrMore>
<ref name="person-element"/>
</oneOrMore>
</element>
</define>
<define name="person-element">
</define>
...
</grammar>
其他語法:
<element name="addressBook">
<zeroOrMore>
<element name="card">
<choice>
<element name="name">
<text/>
</element>
<group>
<element name="givenName">
<text/>
</element>
<element name="familyName">
<text/>
</element>
</group>
</choice>
<optional>
<element name="note">
<text/>
</element>
</optional>
</element>
</zeroOrMore>
</element>
2. XSD
參考文檔: XSD 教程
a. 元素
**簡易元素(simpleContent)😗*只包含文本的元素,它不會包含任何其他的元素或屬性
# 定義
<xs:element name="xxx" type="yyy"/> # 元素
<xs:attribute name="xxx" type="yyy"/> # 屬性
# 默認值和固定值
<xs:element name="color" type="xs:string" default="red"/> # 默認值
<xs:element name="color" type="xs:string" fixed="red"/> # 固定值
複合元素: 包含了其他的元素及/或屬性
<xs:element name="age" type="AgeType"/>
...
<xs:complexType name="AgeType">
# sequence 定義的元素必須以此順序出現
<xs:sequence>
<xs:element name='Name' type="xs:string">
<xs:element name='DoB' type="xs:date">
</xs:sequence>
<xs:attribute name="friend" type="xs:boolean" default="true" />
<xs:attribute name="phone" type="xs:string" />
</xs:complexType>
帶有混合內容的複合類型
<letter>
Dear Mr.
<name>John Smith</name>.
Your order
<orderid>1032</orderid>
</letter>
爲了讓字符數據可以出現在 “letter” 的子元素之間,mixed 屬性必須被設置爲 “true”
<xs:element name="letter">
<xs:complexType mixed="true">
...
</xs:complexType>
</xs:element>
b. 限定(restriction)
限定(restriction)用於爲 XML 元素或者屬性定義可接受的值。對 XML 元素的限定被稱爲 facet
限定 | 描述 |
---|---|
enumeration | 定義可接受值的一個列表 |
pattern | 定義可接受的字符的精確序列 |
length | 定義所允許的字符或者列表項目的精確數目 |
maxInclusive | 定義數值的上限。所允許的值必須小於或等於此值 |
maxLength | 定義所允許的字符或者列表項目的最大數目 |
minInclusive | 定義數值的下限。所允許的值必需大於或等於此值 |
minLength | 定義所允許的字符或者列表項目的最小數目 |
範圍約束: 限定值的範圍爲minInclusive
- maxInclusive
<!-- <age>4</age> -->
<xs:element name="age">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="3"/>
<xs:maxInclusive value="7"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
枚舉約束: 把 XML 元素的內容限制爲一組可接受的值
<xs:element name="car">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Audi"/>
<xs:enumeration value="Golf"/>
<xs:enumeration value="BMW"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
模式約束: 使用正則表達式,把 XML 元素的內容限制定義爲一系列可使用的數字或字母
<xs:element name="letter">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[a-z]"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
c. 擴展(extension)
舉例說明: 通過添加三個元素,對一個已有的 complexType 元素進行擴展
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="fullpersoninfo"/>
<xs:complexType name="personinfo">
<xs:sequence>
<xs:element name="firstname" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="fullpersoninfo">
<xs:complexContent>
<xs:extension base="personinfo">
<xs:sequence>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>)
4. 對比
RelaxNG: grammar-based
- simple/flexible: easy to use
- no mechanism for manipulating datatypes, lists, unions,… [however, can borrow this from XSD]
- no restrictions & extension, no (non-atomic) types
-
in a document, an element of a type derived by restriction from Y can be used in place of an element of type Y
-
this can make writing complex schemas easier & leaves information in IR!
-
but this means that a validating XML parser has to manage a schema’s type hierarchy
-
DTDs and XML Schema (XSD): rule-based
- XML Schema has restrictions on expressing constraints on content models
- e.g., XML Element Declarations Consistent constraint
- applications can do error-checking in a format independent way
三、Schematron
一、基本概念
Schematron 文檔基本上是一組應用於 XML 數據的約束
斷言 (asserts)
對應用於實例文檔的特定條件進行測試,實例文檔要想有效,所有斷言的計算結果都必須是 true
<assert test = "count(//b/(*|text())) = 0">
Error: b elements must be empty
</assert>
報告 (reports)
在這種情況下也對應用的條件進行測試。但是,測試的意義與斷言的意義正好相反。如果測試結果是 true,那麼文檔將處於無效狀態
<report test = "count(//b/(*|text()))!= 0">
Error: b elements must be empty
</report>
example: “At least 1 person for each family”
<pattern>
<rule context="person">
<let name="L" value="@LastName"/>
<report test="count(//family[@name = $L]) = 0">
There has to be a family for each person mentioned,
but <value-of select="$L"/> has none!
</report>
</rule>
</pattern>
<PList>
<person FirstName="Bob" LastName="Builder"/>
<person FirstName="Bill" LastName="Bolder"/>
<person FirstName="Bob" LastName="Milder"/>
<family name="Builder" town="Manchester"/>
<family name="Bolder" town="Bolton"/>
</PList>
# output
Severity: error
Description: There has to be a family for each person mentioned, but Milder has none!
四、PSVI
參考文檔: Post-Schema-Validation Infoset
架構驗證後信息集(Post-Schema-Validation Infoset)
基於 Schema 的驗證完成後,可以按照 Schema 所隱含的數據模型來表達文檔的結構與內容。XML Schema 數據模型包括:
- 樹形結構及數據內容
- 標籤(類型註釋)
- 添加了默認值(元素和屬性)
- 有效性或無效性結果
這些信息的集合即爲 Schema 既驗信息集 (Post-Schema-Validation Infoset (PSVI)). 對於有效的 XML,PSVI 給它賦以特定的“類型”,從而便於以對象方式來處理整個文檔,並應用面向對象程序設計(OOP)範式。
1. 特點說明
假設P1和P2相同:
-
D1和D2可以不相同, 存在結構相同但某些元素上的屬性不同
-
S1與S2可以不相同, S1和S2指定不同的默認值。 那麼它們都不是相似/相同/等價的
2. 舉例說明:
<p:pipeline xmlns:p="http://www.w3.org/ns/xproc" name="main" version="1.0">
<p:validate-with-xml-schema>
<p:input port="schema">
<p:document href="../docs/document.xsd"/>
</p:input>
</p:validate-with-xml-schema>
</p:pipeline>
處理: XML Schema輸出是PSVI,其中可能包含默認屬性和類型信息。 在這裏,我們看到一個默認屬性添加到div元素。
<doc>
<title>Title</title>
<div>
<p>Some paragraph.</p>
</div>
</doc>
<!-- 輸出: 添加了默認值 -->
<doc>
<title>Title</title>
<div class="normal">
<p>Some paragraph.</p>
</div>
</doc>