XML Schema 里对节点取值范围进行限制,本质是把约束施加在简单类型上,而不是直接写在复杂类型定义中。<complexType> 负责描述节点的结构、子元素顺序与数量,而数值边界、字符串长度、枚举值这类限制必须由 <simpleType> 配合 <restriction> 完成。如果在定义产品价格节点时只用 xs:string,写入 abc 这样的数据也能通过校验;只有把该节点绑定到带边界的简单类型,schema 才会真正拦截非法值。

先把 XSD 中两个关键元素区分清楚:<simpleType> 用于创建独立可复用的取值类型,<restriction> 用于在已有类型基础上加限制。这个限制关系可以理解为派生:从 xs:decimal 派生出 priceType,保留十进制特性,同时缩小取值范围。理解了这一点,后面在 <complexType> 里使用受限节点就不会混淆。
一、用 restriction 派生简单类型限制数值范围
XSD 提供多种 constraining facets,它们是 <restriction> 的子元素,用来声明具体边界。最常用的数值边界包括 <minInclusive>、<maxInclusive>、<minExclusive>、<maxExclusive>。前两者表示包含端点的闭区间,后两者表示不包含端点的开区间。例如要把价格限制在 0 到 9999.99 之间且最多两位小数,可以从 xs:decimal 派生一个简单类型。
<xs:simpleType name="priceType">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9999.99"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
代码里 <xs:simpleType> 的 name 属性给类型命名为 priceType;<xs:restriction> 的 base 属性说明派生来源;内部三个 facets 则分别限制最小包含值、最大包含值与小数位数。此时 priceType 的合法值包括 0、0.5、9999.99,但不包括 -0.01、10000、12.345。注意 fractionDigits 只能限制小数位数,并不能决定小数的固定格式,若需要补齐两位小数,应在应用层处理或配合 pattern 完成。
二、在 complexType 元素声明中嵌入受限类型
复杂类型定义中,元素本身只是结构节点,取值限制需要写到元素声明对应的 <simpleType> 里。常见做法有两种:一种是定义一个全局 simpleType,然后在元素声明处通过 type 属性引用;另一种是直接在 <element> 内部写匿名 simpleType。前者可复用,后者只作用于当前元素。
<xs:complexType name="productType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="price">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9999.99"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
上面这个 productType 中,name 节点直接使用内置字符串类型,而 price 节点则通过匿名 simpleType 限制取值。如果希望多个 complexType 共用相同价格规则,推荐把 priceType 提升为全局类型,再在元素声明中写 type="priceType"。不管采用哪种方式,XSD 校验逻辑都一样:先检查节点结构是否符合 complexType,再检查节点内容是否符合其绑定的 simpleType 约束。
<xs:simpleType name="priceType">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9999.99"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="productType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="price" type="priceType"/>
</xs:sequence>
</xs:complexType>
三、使用 enumeration 与 pattern 限制离散值和格式
数值边界适合连续区间,但如果节点只能取少数几个固定值,例如订单状态,枚举限制更直观。<enumeration> 的作用是把基类型的取值空间压缩到指定的几个值。它的 value 属性必须符合基类型的词法规则,否则 schema 解析阶段就会报错。
<xs:simpleType name="orderStatusType">
<xs:restriction base="xs:string">
<xs:enumeration value="pending"/>
<xs:enumeration value="paid"/>
<xs:enumeration value="shipped"/>
<xs:enumeration value="closed"/>
</xs:restriction>
</xs:simpleType>
当取值范围很宽但有固定格式时,可以使用 <pattern> 正则表达式。例如订单编号要求三个大写字母加连字符再加四位数字,就可以写成 [A-Z]{3}-\d{4}。这里的 \d 表示数字字符,反斜杠必须原样保留。pattern 直接作用于字符串的词法空间,因此通常从 xs:string 派生最不容易出错。
<xs:simpleType name="orderCodeType">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]{3}-\d{4}"/>
</xs:restriction>
</xs:simpleType>
需要注意的是,pattern 是完整字符串匹配,不是子串搜索。即使值中间包含符合格式的片段,只要整体不符合正则,校验就不通过。另外,一个简单类型里可以写多个 pattern 限制,它们之间是逻辑或关系,只要满足其中一个即可。
XML Schema复杂类型节点限制修改时间:2026-08-22 11:34:02