自从XML Schema 1.0规范在2001年成为W3C建议以来,开发人员社区已经讨论了该语言的优缺点。 W3C XML Schema工作组已经开发了该语言的下一个版本。 2005年,随着该标准在业界的广泛采用以及与XSLT,XQuery和WSDL等许多其他标准的集成,W3C举办了一个研讨会,以反思用户体验并收集反馈,以帮助指导语言的发展。 该研讨会与社区中其他用户的要求一起,帮助XML Schema工作组确定了标准1.1版本的范围。
在本文中,我们首先概述XML Schema 1.1的一些新功能,然后再深入探讨对规范的Datatypes部分所做的增强。 现在,该标准正式称为XML Schema Definition Language或XSD。 我们将在本文和整个系列中使用此缩写。 有时,当意图明确时,“ XML Schema”和“ schema”也用于引用该语言。
作为读者,请记住,本文是在XML Schema 1.1仍在开发中时编写的。 在XML Schema 1.1成为W3C Recommendation之前,某些细节可能会更改。
XML Schema 1.0的痛点
模式作者经常面临某些挑战。 您可以解决其中的一些问题,从而产生与直觉相反的模式设计。 您可以使用编程语言的代码来处理其他代码。
本节检查一些最常见的问题,并讨论XML Schema 1.1如何帮助解决这些问题。 详细讨论将在本文的后续部分中进行。
内容模型限制
复杂类型可以具有不同种类的内容。 那些允许子元素的元素必然具有<xs:sequence>
, <xs:choice>
或<xs:all>
作为其内容模型。 当通过限制从另一类型派生复杂类型时,两个内容模型都必须满足某些条件。 指定这些条件是为了确保基本类型也允许限制类型所允许的内容。
在XML Schema 1.0中,使用25个大小写的表指定这些条件,并且内容模型必须看起来非常相似才能满足这些条件。 这可能会导致问题:
- 25个案例中的严格规则排除了一些显然有效的推导。
- 该规则允许一些显然无效的派生(也就是说,限制所允许的不只是基数)。
例如,在清单1中 , derived
的类型从base
类型中删除了一个可选元素tns:a
。 这显然是有效的限制,但在XML Schema 1.0中无效。
清单1.派生类型从基本类型中删除了一个可选元素
<complexType name="base">
<complexContent>
<sequence>
<element ref="tns:a" minOccurs="0" maxOccurs="1"/>
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="tns:b"/>
<element ref="tns:c"/>
</choice>
</sequence>
</complexContent>
</complexType>
<complexType name="derived">
<complexContent>
<restriction base="tns:base">
<sequence>
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="tns:b"/>
<element ref="tns:c"/>
</choice>
</sequence>
</restriction>
</complexContent>
</complexType>
在XML Schema 1.1中,删除了25种情况的规则,并用一个简单的概念代替,以反映“目标允许的限制还允许什么”。 上面的示例在XML Schema 1.1中生效。
共同约束
模式作者经常想强制执行涉及多个元素或属性的规则。 例如,“ min
必须小于或等于max
”,或“子元素的数量必须与size
属性匹配”。 此类规则通常称为共现约束或简称为共约束 。
XML Schema 1.0没有提供任何支持共同约束的功能。 在将XML文档加载到内存后,用户有时必须编写Java™或C代码来进行检查。 这会损害可维护性,并使架构的互操作性降低。 一些用户从其他XML验证语言(例如Schematron和Relax NG,请参阅参考资料 )寻求帮助,以获取共约束支持,这使他们本来基于XSD的体系结构变得复杂。
XML Schema 1.1本机支持共约束。 新引入的<xs:assert>
元素可以包含XPath 2.0(请参阅参考资料 )表达式中指定的条件。 清单2显示了一个示例:
清单2. XML Schema 1.1中的共约束
<xs:complexType name="intRange">
<xs:attribute name="min" type="xs:int"/>
<xs:attribute name="max" type="xs:int"/>
<xs:assert test="@min <= @max"/>
</xs:complexType>
模式演变
人们经常发现需要发展他们的模式,添加新信息的扩展。 通配符是为此目的而设计的功能强大的工具。 可以在早期版本的架构中使用它来保留扩展点,而在更高版本中,可以引入具体元素代替通配符。 但是通配符有一些不幸的缺点:
- 非常有争议的唯一粒子归因(UPA)规则使使用可选通配符变得困难。
- 通配符的表达能力不足以描述“除以下内容外的所有内容”。
- 对每个复杂类型重复相同的通配符以使整个架构可扩展很繁琐。
XML Schema 1.1使架构演变变得更加容易。 除其他外,通配符得到了极大的改进。 与明确指定的元素冲突时,它们不再违反UPA,可以排除名称空间列表或名称列表,甚至可以将它们设为默认值。 编写可扩展模式比以往任何时候都容易。
例如,要表示“只有一个名为userName
元素以及在userName
之前或之后的任意数量的任何其他元素”的内容模型,请定义清单3中的内容模型。
清单3. XML Schema 1.0中的内容模型
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
<xs:element ref="tns:userName"/>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
</xs:sequence>
但这在XML Schema 1.0中无效。 遇到名为userName
的元素时,它是否与通配符<xs:any>
或元素声明<xs:element>
匹配是不确定的。 要变通解决此问题,某些人在通配符和元素之间插入分隔符元素。 这行得通,但是使架构和XML文档都很难看。 另一个问题是通配符还允许使用userName
,因此无法执行“一个且只有一个”规则。
在XML Schema 1.1中, 清单3中的纲要代码段变得有效,因为通配符被削弱了,这意味着当元素可以与元素声明或通配符匹配时,元素声明始终优先。 这样可以避免UPA问题。 借助负通配符,您现在可以表达“一个且只有一个userName
以及其他任何内容”规则,如清单4所示。
清单4. XML Schema 1.1中的内容模型
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded"
processContents="skip" notQName="tns:userName"/>
<xs:element ref="tns:userName"/>
<xs:any minOccurs="0" maxOccurs="unbounded"
processContents="skip" notQName="tns:userName"/>
</xs:sequence>
XML模式数据类型
XML Schema规范包括两部分:结构和数据类型(请参阅参考资料 )。 在本节中,我们将介绍XML Schema 1.1部分引入的规范的Datatypes部分中的一些更改。 在以后的文章中,我们将详细介绍有关“结构”部分的更改。
与XQuery 1.0和XPath 2.0数据模型类型对齐
W3C XQuery 1.0,XPath 2.0,XSLT 2.0和XQuery 1.0和XPath 2.0数据模型建议书(请参阅参考资料 )使用的类型系统是W3C XML Schema 1.0建议书的扩展。 除了XML Schema 1.0内置的原始数据类型之外,这些规范还在XML Schema 1.0命名空间中定义了五种其他数据类型,即: anyAtomicType
, untyped
, untypedAtomic
, dayTimeDuration
和yearMonthDuration
。 为了使XML Schema的类型系统与这些规范保持一致,XML Schema 1.1数据类型规范引入了其中的三种数据类型,即: anyAtomicType
, dayTimeDuration
和yearMonthDuration
。
anyAtomicType
anyAtomicType
是一种特殊的XML Schema 1.1内置数据类型,它是通过约束从anySimpleType
派生的。 由于anyAtomicType
是所有原始数据类型的基础,因此anyAtomicTypes
的值和词汇空间是所有原始数据类型的值和词汇空间的并集。 为了更好地解释这一点,请参见下面的XML Schema( 清单5 )和有效的XML文档( 清单6 )。 在此示例中,类型anyAtomicType
的元素可以包含字符串或整数作为有效值。 也可以使用xsi:type
anyAtomicType
转换为从anyAtomicType
派生的更特定的xsi:type
。 应当指出, anyAtomicType
没有定义任何约束方面,因此您不能将其用作用户定义的简单类型的基本类型。
清单5. anyAtomicType的示例XML模式
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="test" xmlns:pfx="test">
<element name="root">
<complexType>
<sequence>
<element name="elanyAtomicType" type="anyAtomicType"
maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</schema>
清单6. anyAtomicType的示例XML文档
<pfx:root xmlns:pfx="test" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<elanyAtomicType>Test</elanyAtomicType>
<elanyAtomicType>12345</elanyAtomicType>
<elanyAtomicType xsi:type="xs:string">Test</elanyAtomicType>
<elanyAtomicType xsi:type="xs:integer">12345</elanyAtomicType>
</pfx:root>
yearMonthDuration
XML Schema 1.0数据类型建议书(请参阅参考资料 )中指定的duration
数据类型是代表一段时间的部分排序类型。 例如,持续时间值P30D和P1M是无法比较的,因为一个月可以包含28到31天之间的任何时间。 为了使持续时间可比较,XML架构1.1引入了两个新的全序数据类型,即: yearMonthDuration
和dayTimeDuration
,通过限制派生duration
。
在XML Schema 1.1中, yearMonthDuration
数据类型通过限制其词法表示以仅包含年和月部分而从duration
派生。 您可以使用正则表达式来表达它:' -?P[0-9]+(Y([0-9]+M)?|M)
'。 年和月分量的值允许使用无符号整数。 可选的减号表示负的yearMonthDuration
。 duration
数据类型的值空间由整数月份和十进制秒数组成。 yearMonthDuration
数据类型的值空间是对秒数属性为零(0)的duration
数据类型的值空间的限制。
一年零六个月的正yearMonthDuration
可以用词法表示为P1Y6M或P18M。 yearMonthDuration
的值是18个月。 有效的yearMonthDuration
值的示例包括P1Y2M
, P12Y
, -P20M
,而以下表示形式无效: P-1Y
, P1Y-1M
和P1YM
。 yearMonthDuration
数据类型已完全排序。 对于任何2 yearMonthDurations
值D1
和D2
,可以建立D1
和D2
之间的排序关系。 也就是说, D1 > D2
或D1 < D2
。
用户定义的数据类型可以通过限制来导出yearMonthDuration
,通过指定允许约束面duration
。 由于yearMonthDuration
是通过duration
的限制得出的,因此它的基本面(有序)是局部的,通过推导保持不变。 但是yearMonthDuration
实际上是完全有序的。
dayTimeDuration
类似于yearMonthDuration
,所述dayTimeDuration
数据类型源自duration
由来自限制其词汇表示只包含的日期和时间(小时,分钟,和秒)分量duration
的数据类型。 这可以通过与正则表达式[^YM]*[DT].*
相匹配的持续时间来表示。 天,小时和分钟组成部分的值不受限制,但允许使用任意无符号xs:integer
。 类似地,秒部分的值允许任意的无符号xs:decimal
。 可选的减号表示dayTimeDuration
为负。 所述的值空间dayTimeDuration
数据类型是的值空间的限制duration
的数据类型具有零个属性值和小数秒值。
一天,两个小时,三分钟和4.5秒的正dayTimeDuration
可以P1DT2H3M4.5S
表示为P1DT2H3M4.5S
。 今年yearMonthDuration
值为93784.5(1 * 24 * 60 * 60 + 2 * 60 * 60 + 3 * 60 + 4.5)分数秒。 请注意,如果天数,小时数,分钟数和秒数为零,则只要存在至少其中之一,就可以从词汇表述中忽略它。 如果dayTimeDuration
仅由几天组成,则指示符T必须不存在。 有效的一些例子dayTimeDuration
包括P1D
, PT25H
, P22DT2H
, PT1H99M5
, 5S
, -PT20M
, -PT60.60S
和无效的例子dayTimeDuration
是P-5D
, P1D1M1H1S
, PDT1M
, P5H
和P1DT
。 与yearMonthDuration
一样, dayTimeDuration
数据类型也已完全排序。
通过限制从dayTimeDuration
派生的数据类型可以指定与duration
数据类型相同的约束方面。 请注意, yearMonthDuration
和dayTimeDuration
的whitespace
方面的值固定为collapse
,无法更改。
清单7展示了一个有效的XML Schema 1.1片段,该片段使用yearMonthDuration
和dayTimeDuration
数据类型。
清单7. yearMonthDuration和dayTimeDuration的示例XML模式
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="test" xmlns:pfx="test">
<simpleType name="ymdBase">
<restriction base="yearMonthDuration">
<minInclusive value="P1Y6M"/>
</restriction>
</simpleType>
<simpleType name="ymdDerived">
<restriction base="ymdBase">
<minInclusive value="P19M"/>
</restriction>
</simpleType>
<simpleType name="dtdBase">
<restriction base="dayTimeDuration">
<maxInclusive value="-P2DT2H"/>
</restriction>
</simpleType>
<simpleType name="dtdDerived">
<restriction base="dtdBase">
<maxInclusive value="-P51H"/>
</restriction>
</simpleType>
<element name="root">
<complexType>
<sequence>
<element name="elYearMonthDuration" type="ymdDerived"/>
<element name="elDayTimeDuration" type="dtdDerived"/>
</sequence>
</complexType>
</element>
</schema>
清单7展示了一个有效的XML Schema 1.1片段,该片段使用yearMonthDuration
和dayTimeDuration
数据类型。 简单类型ymdDerived
限制了基本类型ymdBase
,该类型又限制了使用minInclusive
构面的XML Schema yearMonthDuration
内置数据类型。 由于yearMonthDuration
已完全排序,因此派生类型ymdDerived
的值P19M大于基本类型ymdBase
的值P1Y6M,这使其成为有效限制。 类似地,简单类型dtdDerived
限制了基本类型dtdBase
,而基础类型又限制了使用maxInclusive
方面的XML Schema dayTimeDuration
内置数据类型。 在这种情况下,派生类型dtdDerived
的-P51H的负持续时间小于基本类型-P2DT2H的负持续时间。 的元件, root
,包含子元素elYearMonthDuration
和elDayTimeDuration
类型ymdDerived
和dtdDerived
分别。
precision十进制
precisionDecimal
是XML Schema 1.1中引入的新类型,以支持新的IEEE-754浮点十进制类型。 它与decimal
不同,因为精度十进制数字不仅包含数字值,而且还保留算术精度。 precisiontDecimal
还包括正无穷大( +INF
)和负无穷大( -INF
)的值,而不是数字( NaN
)的值。 它还可以区分正零(+0)和负零(-0)。
precisionDecimal
的词汇空间是所有十进制数字(带或不带小数点),科学(指数)表示法以及字符串“ INF
”,“ +INF
”,“ -INF
”和“ Na
”的-INF
。 N'。
通过限制条件从precisionDecimal
派生的用户定义数据类型可以指定与decimal
相同的约束方面。 另外,引入了两个新的约束方面maxScale
和minScale
,以允许派生类型缩小precisionDecimal
的值空间。 maxScale
设置上限,而minScale
设置precisionDecimal
值的算术精度下限。
在清单8中 ,我们定义了一个新的price
类型,该price
类型接受-999,999.99
到999,999.99
之间的值。
清单8.使用precisionDecimal的示例XML模式片段
<xs:simpleType name='price'>
<xs:restriction base='xs:precisionDecimal'>
<xs:totalDigits value='8'/>
<xs:minScale value='2'/>
<xs:maxScale value='2'/>
</xs:restriction>
</xs:simpleType>
使用NaN
时要记住的一件事是,它与任何其他值(包括其自身)都无法比拟。 因此,如果对任何边界面( minInclusive
, maxInclusive
, minExclusive
或maxExclusive
)使用NaN
,则最终将得到具有空值空间的数据类型。
同样,将NaN
包含在枚举中也不会使其接受NaN
值。 如果希望将NaN
作为值空间的一部分,请定义一个联合类型,该联合类型包括仅NaN
数据类型(通过指定值为“ NaN
”的模式构面)。
时区与时区偏移
XML Schema 1.0规范中指定的与date
, time
和dateTime
相关的数据类型包括一个可选的时区,形式为(('+' | '-') hh ':' mm) | 'Z'
(('+' | '-') hh ':' mm) | 'Z'
。 将时区值添加到世界标准时间(UTC)dateTime时,它将在该时区中生成日期和时间。
尽管XML Schema 1.0规范意味着时区偏移,但是它使用术语时区来描述它,这引起了一些混淆,因为时区和时区偏移代表了两个不同的概念。 时区标识特定的位置或区域(例如,太平洋时间),而时区偏移量是UTC与特定时区(例如11:00-05:00
)之间的小时和分钟差。 XML Schema 1.1规范已纠正了此问题,现在可以区分时区和时区偏移量。
seconds秒
leap秒是在3月,6月,10月或12月的最后一天加上的额外秒数,这意味着该月一天中的最后一分钟有60秒以上。 添加秒以使UTC保持在观测天文时间的0.9秒以内。
因为XML Schema 1.1规范中定义的与日期和时间相关的类型不支持leap秒,所以不能使用它们表示UTC中添加added秒的任何一天的最后一秒。 这种日期的一个示例是1972-06-30。 如果跟踪of秒很重要,则用户需要在应用程序级别进行适当的更改以处理此类日期。
实现定义的简单类型和构面
XML Schema规范定义了处理器可以理解并为其提供实现的许多原始类型,例如string
, boolean
和double
。 许多系统需要的类型比规范中定义为内置的类型更多。 您可以通过从现有需求中派生类型来满足其中一些需求,但不能满足其他需求。
实现定义的原始类型
XML Schema 1.1现在允许XML Schema处理器的实现者定义自己的原始简单类型。 由每个XML Schema处理器决定是否识别此类类型。
实现者需要遵循以下规则:
- 使用
anyAtomicType
作为基本类型。 - 确定应用哪些约束方面以及应用时它们的含义(注意:您必须包括一个
whiteSpace
方面)。 - 使用不同于
http://www.w3.org/2001/XMLSchema
(由W3C控制)的目标名称空间,定义引用新类型的机制。 - 定义新类型的词法空间,值空间和词法映射。
- 定义平等关系。
- 定义基本面的值。
作为XML处理器的实现者,我们可以定义一种特殊的date
数据类型,该数据类型与day-month-year的格式一致,但使用各种分隔符,而不仅仅是连字符(-)。 按照上面定义的规则,我们使用anyAtomicType
作为基本类型,并定义一个新的命名空间,我们可以将其称为“ http://www.example.com/XMLSchema-primitiveTypes”。 我们希望我们的日期以以下格式表示:日,分隔符,月,分隔符,年。 在date
数据类型的词汇空间中,日,月和年的表示形式将具有与XML Schema 1.1中定义的表示形式相同的规则。 我们希望分隔符为三个值之一:句点(。),连字符(-)或斜杠(/)。
我们还定义了在实施过程中将支持的方面。 基本方面可以包括以下方面和值:
- 订购:部分
- 有界:假
- 基数:无限大
- 数值:假
根据规则,我们需要包含一个whiteSpace
面,并将其定义为“ collapsed”值,该值适用于date
和所有派生数据类型。 根据XML Schema 1.1规范,我们还可以根据需要定义其他约束方面和值,例如:
- 模式
- 枚举
- maxInclusive
- maxExclusive
- minInclusive
- minExclusive
- 断言
- dateSeparator(实现定义)
使用此定义,“ 2008-11-01
”,“ 2008.11.01
”和“ 2008/11/01
”都是日期的有效词法表示,它们都表示同一天“ 2008年11月1日”。
实现定义的方面
XML Schema规范定义了一组约束面(例如minInclusive
或maxLength
),您可以将其应用于简单类型。 约束构面是可用于在派生期间控制简单类型的值空间的构造。 具有模式意识的处理器可以理解并支持约束方面。
与实现定义的原始类型相似,XML Schema 1.1允许实现者定义自己的约束构面,而XML Schema处理器是否支持此类构面则由其决定。
以下是一些要遵循的规则:
- 定义构面的属性。
- 定义构面的行为。
- 定义一种机制来引用具有
http://www.w3.org/2001/XMLSchema
以外的名称空间的新构面(因为W3C控制该名称空间)。 - 定义新约束面适用的原始数据类型。
在清单9中 ,您将看到XML处理器实现者如何定义dateSeparator
构面,该dateSeparator
面将分隔符限制在实现定义的date
的值空间以及从中定义的所有数据类型中。
清单9.一个实现定义的方面的示例
<dateSeparator
fixed = boolean : false
id = ID
value = '-' | '.' | '/'
... >
(optional element content here)
...
</dateSeparator>
构面定义可能会使用fixed, id,
和value
之外的非模式命名空间定义其他属性。 然后,任何派生的数据类型都可以通过应用dateSeparator
构面来限制实现定义的date
的值空间。
现在查看用户如何使用此实现定义的数据类型及其实现定义的方面。 在清单10中 ,我们定义了一个新类型specialDate
,它使用新的构面来限制date
的表示,以仅接受以斜杠(/)作为分隔符的值。
清单10.一个基于实现定义的类型的派生类型的示例
<xs:simpleType name="specialDate">
<xs:restriction base="xyz:date">
<xyz:dateSeparator value="/" />
<xs:restriction>
</xs:simpleType>
现在specialDate
只允许“ 2008/11/01
”,而不允许“ 2008-11-01
”和“ 2008.11.01
”。
结论
在本文中,我们对XML Schema 1.1进行了概述,重点介绍了XML Schema 1.0的痛点,并简要介绍了XML Schema 1.1如何通过使用通配符通过内容模型限制,协同约束和模式演变的示例来解决其中的几个问题。 然后,我们深入研究了对规范的数据类型部分的增强,包括新的数据类型以及对实现定义的原始类型和构面的允许。 在本系列的第2部分中,我们将进一步探索新的共约束功能,特别是断言和条件类型分配机制。
翻译自: https://www.ibm.com/developerworks/xml/library/x-xml11pt1/index.html