我可以根据子 Type 元素值验证多态 XML 元素吗?
Can I validate polymorphic XML elements based on a child Type element value?
我想验证多态 Shape
元素,由 Type
子元素(not 属性)值区分。下面是兄弟 Circle 和 Rectangle Shape
元素。圈子有一个Radius
,只有1个Point
。矩形没有 Radius
而有 4 个 Point
元素:
<?xml version="1.0" encoding="UTF-8" ?>
<Shapes>
<Shape>
<Type>Circle</Type>
<ID>A1234</ID>
<Label>This is round</Label>
<Radius>5.4</Radius>
<Points>
<Point>
<X>5.00</X>
<Y>2.00</Y>
</Point>
</Points>
</Shape>
<Shape>
<Type>Rectangle</Type>
<ID>B4567</ID>
<Label>This is not round</Label>
<Points>
<Point>
<X>0.00</X>
<Y>0.00</Y>
</Point>
<Point>
<X>4.00</X>
<Y>0.00</Y>
</Point>
<Point>
<X>4.00</X>
<Y>2.00</Y>
</Point>
<Point>
<X>0.00</X>
<Y>2.00</Y>
</Point>
</Points>
</Shape>
</Shapes>
这是一个非功能性架构,与我希望做的一致:
<xsd:simpleType name="ShapeTypeEnum">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Circle"/>
<xsd:enumeration value="Rectangle"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="ShapeBase">
<xsd:sequence>
<xsd:element name="Type" type="ShapeTypeEnum"/>
<xsd:element name="ID" type="xsd:string"/>
<xsd:element name="Label" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Shape" type="Circle">
<xsd:complexContent>
<xsd:extension base="ShapeBase">
<xsd:all>
<xsd:element name="Radius" type="xsd:decimal"/>
<xsd:element name="Points">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="Point" type="Point"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Shape" type="Rectangle">
<xsd:complexContent>
<xsd:extension base="ShapeBase">
<xsd:all>
<xsd:element name="Points">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="4" maxOccurs="4" name="Point" type="Point"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Point">
<xsd:all>
<xsd:element name="X" type="xsd:decimal"/>
<xsd:element name="Y" type="xsd:decimal"/>
</xsd:all>
</xsd:complexType>
行 <xsd:complexType name="Shape" type="Rectangle">
和 <xsd:complexType name="Shape" type="Circle">
不起作用。是否可以根据子元素 (Type
) 的值验证具有不同模式部分的同名元素?
在XSD 1.0 中,无法完成。在 XSD 1.1 中,它可以使用断言。
虽然即使使用断言,也不是那么容易(如果 Type
是一个属性会容易得多)。您需要定义一个内容模型,该模型实际上是针对不同形状的所有不同模型的联合(您不能在此示例中使用简单的 xs:choice
,因为它会违反 UPA),然后您需要定义断言,例如
<xs:assert test="exists(radius) = (type = 'Circle')"/>
<xs:assert test="count(points) = 4 or type != 'Rectangle'"/>
XSD 1.1 在 Altova、Saxon 和 Xerces 中受支持,但例如 Microsoft 模式处理器不支持。
Michael Kay 已经解释了如何使用 xs:assert
来实现您请求的验证,假设您的 XML 设计无法更改。但是,值得指出的是,您的 XML 设计本身存在本质问题:
通用元素名称加类型是 XML
中的反模式
不好
<Thing>
<Type>TrueNature</Type>
<!-- ... -->
</Thing>
XSD 1.1和断言需要基于TrueNature
.
进行约束
另请参阅:
- Vary type in XSD according to element value?
更好
<Thing type="TrueNature">
<!-- ... -->
</Thing>
XSD 1.1 and assertions or 需要根据TrueNature
.
进行约束
最佳
<TrueNature>
<!-- ... -->
</TrueNature>
XSD 1.0 后缀,因为元素名称本身就反映了它的真实性质。
我想验证多态 Shape
元素,由 Type
子元素(not 属性)值区分。下面是兄弟 Circle 和 Rectangle Shape
元素。圈子有一个Radius
,只有1个Point
。矩形没有 Radius
而有 4 个 Point
元素:
<?xml version="1.0" encoding="UTF-8" ?>
<Shapes>
<Shape>
<Type>Circle</Type>
<ID>A1234</ID>
<Label>This is round</Label>
<Radius>5.4</Radius>
<Points>
<Point>
<X>5.00</X>
<Y>2.00</Y>
</Point>
</Points>
</Shape>
<Shape>
<Type>Rectangle</Type>
<ID>B4567</ID>
<Label>This is not round</Label>
<Points>
<Point>
<X>0.00</X>
<Y>0.00</Y>
</Point>
<Point>
<X>4.00</X>
<Y>0.00</Y>
</Point>
<Point>
<X>4.00</X>
<Y>2.00</Y>
</Point>
<Point>
<X>0.00</X>
<Y>2.00</Y>
</Point>
</Points>
</Shape>
</Shapes>
这是一个非功能性架构,与我希望做的一致:
<xsd:simpleType name="ShapeTypeEnum">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Circle"/>
<xsd:enumeration value="Rectangle"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="ShapeBase">
<xsd:sequence>
<xsd:element name="Type" type="ShapeTypeEnum"/>
<xsd:element name="ID" type="xsd:string"/>
<xsd:element name="Label" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Shape" type="Circle">
<xsd:complexContent>
<xsd:extension base="ShapeBase">
<xsd:all>
<xsd:element name="Radius" type="xsd:decimal"/>
<xsd:element name="Points">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="Point" type="Point"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Shape" type="Rectangle">
<xsd:complexContent>
<xsd:extension base="ShapeBase">
<xsd:all>
<xsd:element name="Points">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="4" maxOccurs="4" name="Point" type="Point"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="Point">
<xsd:all>
<xsd:element name="X" type="xsd:decimal"/>
<xsd:element name="Y" type="xsd:decimal"/>
</xsd:all>
</xsd:complexType>
行 <xsd:complexType name="Shape" type="Rectangle">
和 <xsd:complexType name="Shape" type="Circle">
不起作用。是否可以根据子元素 (Type
) 的值验证具有不同模式部分的同名元素?
在XSD 1.0 中,无法完成。在 XSD 1.1 中,它可以使用断言。
虽然即使使用断言,也不是那么容易(如果 Type
是一个属性会容易得多)。您需要定义一个内容模型,该模型实际上是针对不同形状的所有不同模型的联合(您不能在此示例中使用简单的 xs:choice
,因为它会违反 UPA),然后您需要定义断言,例如
<xs:assert test="exists(radius) = (type = 'Circle')"/>
<xs:assert test="count(points) = 4 or type != 'Rectangle'"/>
XSD 1.1 在 Altova、Saxon 和 Xerces 中受支持,但例如 Microsoft 模式处理器不支持。
Michael Kay 已经解释了如何使用 xs:assert
来实现您请求的验证,假设您的 XML 设计无法更改。但是,值得指出的是,您的 XML 设计本身存在本质问题:
通用元素名称加类型是 XML
中的反模式不好
<Thing>
<Type>TrueNature</Type>
<!-- ... -->
</Thing>
XSD 1.1和断言需要基于TrueNature
.
另请参阅:
- Vary type in XSD according to element value?
更好
<Thing type="TrueNature">
<!-- ... -->
</Thing>
XSD 1.1 and assertions or TrueNature
.
最佳
<TrueNature>
<!-- ... -->
</TrueNature>
XSD 1.0 后缀,因为元素名称本身就反映了它的真实性质。