说说 xml schema


简单说 xml schema 就是用 xml 来描述 xml 格式的特定 xml 文件.通常文件后缀是` xsd`, 它来自于` XML Schema Definition` 的简写.
看看最简单的例子:

```
<?xml version="1.0"?>
<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 文件描述了怎么样一个` xml` 文件呢? 其实从字面的大概格式我们可以看出, 它可能描述的就是这样一个 xml:

```
<?xml version="1.0"?>
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>
```

###xsd 文件都做了什么呢? 
- 它可以规定究竟有什么元素和属性可以出现在被描述的 xml 文件中
- 一个 xml 根节点到底可以包含什么子元素
- 元素或者属性的字段类型
- 元素和属性的默认值等

### 为什么要学习 XML Schema 呢?

在 xml 的世界中, 我们经常会遇到各种各样的不同的 xml 文件.他们通常都是通过 xml schema 来规范约束的, 区别于 DTD 文件的是它本身就是 xml 文件.

### XML schema 支持数据类型

这个可能是区别于其他约束 xml 的描述文件的最大特定

- 它可以很容易的描述这个文件到底有什么内容
- 验证数据的准确性
- 定义数据
- 数据格式
- 不用的数据格式之间的转换


### xml schema 继续使用 xml 语法

- 你不需要多学习其他的语言语法等
- 你用 xml 编辑器就可以编辑 schema
- 你可以通过 xml 的读取方式来解析 schema 文件
- 通过 xml 文件可以生成 schema 文件
- 可以通过` XSLT` 来转换格式

XML schemas 是可以扩展的因为它是 xml 写就

有了这个扩展性就可以做更多的事情:

- 复用 schema
- 定义新是数据类型基于标准的类型
- 在一个 xml 文档中引用多个 schema 文件


### xml schema 增强的数据通信的安全性

当发送数据到对方的时候,双方都能够到期望的结果是必须的. 通过 xml schema, 发送方可以描述数据以至于让接收方能够理解.
例如一个数据`03-11-2017`是什么意思呢, 是3月11号还是11月3号呢?
但是通过 xml 的元素表示,它就是简单的:

```
<date type='date'>2017-03-11</date>
```

这样双方都理解了它是一个` date` 格式的数据, 就是` YYYY-MM-DD` 的格式.

### 格式好并不够

一个格式完好的 xml 文档它是符合 `xml 语法`的存在, 如:

- 必须以 xml 定义说明开始
- 必须有一个根节点
- 开始符必须和结束节点匹配
- 元素大小写敏感
- 所有的元素需要结束
- 所有元素需要正确的嵌套
- 所有的属性值应该括号包围
- 实体必须有特定的字符描述.

## XSD 的<schema>元素

对于 xml schema 文件来说, `<schema>` 是它的根节点.

```
<?xml version="1.0"?>

<xs:schema>
...
...
</xs:schema>
```

这个`<schema>`可以包含很多的属性, 看上去像这样:

```
<?xml version="1.0"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://www.w3schools.com"
xmlns="https://www.w3schools.com"
elementFormDefault="qualified">
...
...
</xs:schema>
```

而其中

```
xmlns:xs="http://www.w3.org/2001/XMLSchema"
```
就表明了这个 schema 文件里用到的元素和数据类型都是来自`"http://www.w3.org/2001/XMLSchema" `这个命名空间里的. 同时指定所有来自这个命名空间里的元素和数据类型都应该使用` xs` 作为前缀.

```
targetNamespace="https://www.w3schools.com"

```

它说明了定义在这个schema的元素*( note, to, from, heading, body)都是来自这个`https://www.w3schools.com" `命名空间的,
而`xmlns="https://www.w3schools.com"`表明它是默认的命名空间, `elementFormDefault="qualified"`是表明所有使用该 schema的 xnl 文件里元素都应该使用命名空间约束.

## 引用这个 schema 文件到 xml 里

```
<?xml version="1.0"?>

<note xmlns="https://www.w3schools.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.w3schools.com note.xsd">

<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
```

这里, `xmlns="https://www.w3schools.com"`它说明默认的命名空间定义,也就是说所有在这里定义出现的元素都是从这个 schema 的命名空间里出现的.

而一旦你有了 xml schema 实例的命名空间,`xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"` 你可以使用` schemaLocation` 属性来定义,它有两个值, 通过空格隔开, 第一个是命名空间, 第二是 xml schema 文件的地址.

```
xsi:schemaLocation="https://www.w3schools.com note.xsd"
```


## XSD 的简单元素

XSD 终归主干一件事情就是定义 xml 文件里的元素.
一个简单的元素也就是说它只能够包含文本,不能够包含子元素或者属性等.

- 如何定义呢:

```
<xs:element name="xxx" type="yyy"/>
```
这里的`xxx` 就是元素的名称, 而`yyy` 就是元素的数据类型.
xml schema 内置了很多的数据类型:

xs:string
xs:decimal
xs:integer
xs:boolean
xs:date
xs:time

例子:

如这个 xml 文件:

```
<lastname>Refsnes</lastname>
<age>36</age>
<dateborn>1970-03-27</dateborn>
```

它实际对应的 xsd 就是:

```
<xs:element name="lastname" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
<xs:element name="dateborn" type="xs:date"/>
```

### 而对于简单元素的默认和固定值又是什么样子

简单元素可以指定默认值或者是固定值.

```
<xs:element name="color" type="xs:string" default="red"/>
# or
<xs:element name="color" type="xs:string" fixed="red"/>

```

# xsd 的属性

所有的属性都是按照简单元素的方式来定义的

- 什么是属性呢?
简单元素不能够有属性,如果一个元素有了属性,那它就是一个复合类型,但是这个属性它本身是以简单元素声明的.

- 怎么定义?

```
<xs:attribute name="xxx" type="yyy"/>
```

其实上面这个虽然是属性的定义,但是和简单元素也基本上一样的, `xxx` 就是名字,而` yyy` 就是类型

```
xs:string
xs:decimal
xs:integer
xs:boolean
xs:date
xs:time
```

例子,

```
# 如这个元素

<lastname lang="EN">Smith</lastname>
#对应的 xsd

<xs:attribute name="lang" type="xs:string"/>
```

同样对应属性的默认值和固定值:

```
<xs:attribute name="lang" type="xs:string" default="EN"/>

# or

<xs:attribute name="lang" type="xs:string" fixed="EN"/>
```

另外对于属性,它本身还可以是可选的

```
<xs:attribute name="lang" type="xs:string" use="required"/>
```

# xsd 里对于值的约束

对于元素或者属性的值, 都是可以进行约束的.如下面的约束例子:

```
<xs:element name="age">
  <xs:simpleType>
    <xs:restriction base="xs:integer">
      <xs:minInclusive value="0"/>
      <xs:maxInclusive value="120"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>
```

它就约束了` age` 这个元素的值应该是`0-120`的.

而且还可以这样约束一个值只能是 set 里的一项:

```
<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>
```

同样上面的写法可以变换成用来约束它的一个属性:

```
<xs:element name="car" type="carType"/>

<xs:simpleType name="carType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="Audi"/>
    <xs:enumeration value="Golf"/>
    <xs:enumeration value="BMW"/>
  </xs:restriction>
</xs:simpleType>
```

接着我们就来说说 xsd 里怎么描述复杂类型吧

# xsd complex 元素

所谓一个复杂元素就是它还包含了子元素或者属性

- 什么是复杂元素

一个复杂元素就是包含了子元素或者属性的元素, 有四种:

- 空元素
- 元素只包含了其他元素
- 元素只包含了文本
- 元素包含了其他元素或者文本.

*这里说的元素都可以有属性

#### 复杂元素

```
# A complex XML element, "product", which is empty:
<product pid="1345"/>
# A complex XML element, "employee", which contains only other elements:

<employee>
  <firstname>John</firstname>
  <lastname>Smith</lastname>
</employee>
# A complex XML element, "food", which contains only text:

<food type="dessert">Ice cream</food>

#A complex XML element, "description", which contains both elements and text:

<description>
It happened on <date lang="norwegian">03.03.99</date> ....
</description>
```

### 怎么定义复杂元素

```
<employee>
  <firstname>John</firstname>
  <lastname>Smith</lastname>
</employee>
```

我们可以通过2中方式来定义复杂元素.

1. 就是直接通过复杂类型来生命元素:


```
<xs:element name="employee">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="firstname" type="xs:string"/>
      <xs:element name="lastname" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
```

这个声明方法里只有` employee` 是可以指定为复杂类型的, 主要对于它的子元素` firstname` 和` lastname` 是通过`<sequence>`来围绕的, 这就说明需要按照声明的顺序来书写.

2. 这个` employee` 元素可以有一个类型的属性来引用到一个复杂元素.

```
<xs:element name="employee" type="personinfo"/>

<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:element name="employee" type="personinfo"/>
<xs:element name="student" type="personinfo"/>
<xs:element name="member" type="personinfo"/>

<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: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>
```

## xsd 空元素

一个所谓的空复杂元素就是它不能够有`内容`,只能有属性

```
<product prodid="1345" />
```

```
<xs:element name="product">
  <xs:complexType>
    <xs:attribute name="prodid" type="xs:positiveInteger"/>
  </xs:complexType>
</xs:element>
```


## xsd 定义只有元素的复杂元素

```
<person>
  <firstname>John</firstname>
  <lastname>Smith</lastname>
</person>
```

可以这样定义:
```
<xs:element name="person" type="persontype"/>

<xs:complexType name="persontype">
  <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
  </xs:sequence>
</xs:complexType>
```

## xsd 只包含文本

## xsd 复合元素

如

```
<letter>
  Dear Mr.<name>John Smith</name>.
  Your order <orderid>1032</orderid>
  will be shipped on <shipdate>2001-07-13</shipdate>.
</letter>
```

```
<xs:element name="letter" type="lettertype"/>

<xs:complexType name="lettertype" mixed="true">
  <xs:sequence>
    <xs:element name="name" type="xs:string"/>
    <xs:element name="orderid" type="xs:positiveInteger"/>
    <xs:element name="shipdate" type="xs:date"/>
  </xs:sequence>
</xs:complexType>
```


ref

- https://www.w3schools.com/xml/