XML 简单类型由属性驱动的元素的架构
XML schema for element whose simple type is driven by an attribute
我想为包含选项的文档编写一个 XML 架构 (xsd 1.1)。每个选项都有一个名称和一个类型(如布尔值、整数、字符串等)以及与该类型匹配的数据。类型列表是固定的,但很长。 (为简单起见,清单 3 中仅列出了 3 个。)
我如何做到这一点而不需要大量重复?
用例 1
这是此架构的有效文档..
清单 1:
<abc:options>
<abc:option name="is-enabled" type="boolean">false</abc:option>
<abc:option name="wing-span" type="float">1.2</abc:option>
</abc:options>
用例 2
此文档对此架构无效,因为 @type 属性的简单类型位错误。
<abc:options>
<abc:option name="is-enabled" type="boolean">24</abc:option>
<abc:option name="wing-span" type="float">this-is-not-a-number!</abc:option>
</abc:options>
到目前为止我已经尝试过...
清单 3 是我迄今为止的尝试。但这很糟糕,因为我必须为每种数据类型重新声明 @name 属性。有更好的解决方案吗?也就是说,我不必为每种可能的数据类型重新声明 @name 属性。
清单 3:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:abc="http://www.example.com"
targetNamespace="http://www.example.com"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="options">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="abc:option" type="option-Type"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="option-Datum-Type">
<xs:restriction base="xs:string">
<xs:enumeration value="boolean"/>
<xs:enumeration value="integer"/>
<xs:enumeration value="float"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="option-Type-boolean">
<xs:simpleContent>
<xs:extension base="xs:boolean">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="abc:option-Datum-Type" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="option-Type-string">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="abc:option-Datum-Type" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="option-Type-float">
<xs:simpleContent>
<xs:extension base="xs:double">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="abc:option-Datum-Type" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="option-Type">
<xs:alternative test="@type='boolean'" type="abc:option-Type-boolean"/>
<xs:alternative test="@type='string'" type="abc:option-Type-string" />
<xs:alternative test="@type='float'" type="abc:option-Type-float" />
<xs:alternative type="xs:error"/>
</xs:complexType>
</xs:schema>
如果类型只能是原子类型之一,您可以像这样使用 xs:assert
:
<xs:complexType name="option-Type">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="xs:string" use="required" />
<xs:assert
test="if (@type='boolean') then . castable as xs:boolean
else if (@type='float') then . castable as xs:float
else if (@type='int') then . castable as xs:int
else if (@type='string') then . castable as xs:string
else false()"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
备注:
您不需要声明任何新类型。如果你愿意,你甚至可以跳过枚举的声明。
使用这种方法,您需要为每种新的可能类型换行(您实际上并不需要换行,但在不同的行中使用每种类型很容易阅读)。
如果你觉得更清楚可以用[=13=]代替.
请注意,如果 XPath 2.0 具有类似于 javascript[=54= 的 eval 函数,这种方法将是多么简单] 和其他语言 eval 函数:
<xs:assert test="eval(text() || ' castable as xs:' || @type)"/>
虽然 eval/parse 函数将被添加到 XPath 3.0 规范中,但我认为它最终没有已添加。
与 instance of
不同,您不能将 ?
以外的列表(*
、+
)与 castable as
运算符一起使用。您只能使用这种方法使用原子类型。
转换为字符串 string 应该总是成功,因为类型被声明为 xs:string.
我想为包含选项的文档编写一个 XML 架构 (xsd 1.1)。每个选项都有一个名称和一个类型(如布尔值、整数、字符串等)以及与该类型匹配的数据。类型列表是固定的,但很长。 (为简单起见,清单 3 中仅列出了 3 个。)
我如何做到这一点而不需要大量重复?
用例 1
这是此架构的有效文档..
清单 1:
<abc:options>
<abc:option name="is-enabled" type="boolean">false</abc:option>
<abc:option name="wing-span" type="float">1.2</abc:option>
</abc:options>
用例 2
此文档对此架构无效,因为 @type 属性的简单类型位错误。
<abc:options>
<abc:option name="is-enabled" type="boolean">24</abc:option>
<abc:option name="wing-span" type="float">this-is-not-a-number!</abc:option>
</abc:options>
到目前为止我已经尝试过...
清单 3 是我迄今为止的尝试。但这很糟糕,因为我必须为每种数据类型重新声明 @name 属性。有更好的解决方案吗?也就是说,我不必为每种可能的数据类型重新声明 @name 属性。
清单 3:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:abc="http://www.example.com"
targetNamespace="http://www.example.com"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="options">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="abc:option" type="option-Type"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="option-Datum-Type">
<xs:restriction base="xs:string">
<xs:enumeration value="boolean"/>
<xs:enumeration value="integer"/>
<xs:enumeration value="float"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="option-Type-boolean">
<xs:simpleContent>
<xs:extension base="xs:boolean">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="abc:option-Datum-Type" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="option-Type-string">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="abc:option-Datum-Type" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="option-Type-float">
<xs:simpleContent>
<xs:extension base="xs:double">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="abc:option-Datum-Type" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="option-Type">
<xs:alternative test="@type='boolean'" type="abc:option-Type-boolean"/>
<xs:alternative test="@type='string'" type="abc:option-Type-string" />
<xs:alternative test="@type='float'" type="abc:option-Type-float" />
<xs:alternative type="xs:error"/>
</xs:complexType>
</xs:schema>
如果类型只能是原子类型之一,您可以像这样使用 xs:assert
:
<xs:complexType name="option-Type">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="xs:string" use="required" />
<xs:assert
test="if (@type='boolean') then . castable as xs:boolean
else if (@type='float') then . castable as xs:float
else if (@type='int') then . castable as xs:int
else if (@type='string') then . castable as xs:string
else false()"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
备注:
您不需要声明任何新类型。如果你愿意,你甚至可以跳过枚举的声明。
使用这种方法,您需要为每种新的可能类型换行(您实际上并不需要换行,但在不同的行中使用每种类型很容易阅读)。
如果你觉得更清楚可以用[=13=]代替
.
请注意,如果 XPath 2.0 具有类似于 javascript[=54= 的 eval 函数,这种方法将是多么简单] 和其他语言 eval 函数:
<xs:assert test="eval(text() || ' castable as xs:' || @type)"/>
虽然 eval/parse 函数将被添加到 XPath 3.0 规范中,但我认为它最终没有已添加。
与
instance of
不同,您不能将?
以外的列表(*
、+
)与castable as
运算符一起使用。您只能使用这种方法使用原子类型。转换为字符串 string 应该总是成功,因为类型被声明为 xs:string.