我很谨慎,这可能会产生讨论而不是答案,但不过......
我目前有一个XML,我设计的主要目标是使其简洁易读;这对我来说意味着偏爱元素属性并最大限度地减少词汇量:
<?xml version='1.0'?>
<Calculation jobId='XI5-332123' user='wombat' time='2009-04-22T14:04:00Z' version='1'>
<Model fileName='Simulate_TestModelSpecifications' processName='Simulate_TestModelSpecifications' password='Simulate_TestModelSpecifications'/>
<Simulation>
<ModelSpecification name='realParam' type='real' value='5.4864'/>
<ModelSpecification name='intParam' type='integer' value='7'/>
<ModelSpecification name='boolParam' type='boolean' value='true'/>
<ModelSpecification name='realArrayParam' type='real' numElements='2'>
<ArrayElement value='1.0'/>
<ArrayElement value='2.0'/>
</ModelSpecification>
<ModelSpecification name='intArrayParam' type='integer' numElements='2'>
<ArrayElement value='5'/>
<ArrayElement value='6'/>
</ModelSpecification>
<ModelSpecification name='boolArrayParam' type='boolean' numElements='2'>
<ArrayElement value='true'/>
<ArrayElement value='false'/>
</ModelSpecification>
<ModelSpecification name='Var1' type='real' value='20.0'/>
<ModelSpecification name='Var2' type='real' numElements='2'>
<ArrayElement value='30.0'/>
<ArrayElement value='40.0'/>
</ModelSpecification>
<ModelSpecification name='scalarSelector' type='string' value='apple'/>
<ModelSpecification name='arraySelector' type='string' numElements='3'>
<ArrayElement value='red'/>
<ArrayElement value='yellow'/>
<ArrayElement value='blue'/>
</ModelSpecification>
<ReportVariable pathName='myUnit.Var1'/>
<ReportVariable pathName='myUnit.Var2(1)'/>
<ReportVariable pathName='myUnit.Var2(2)'/>
</Simulation>
</Calculation>
现在出现的问题是它是否可以通过XSD完全验证?如果不能,那么一些验证是否必须在SAX解析器(也在我的控制下)中实现是否重要?
我对XML模式的经验非常(非常)有限,但据我所知,验证此XML有3个潜在的棘手问题:
<ArrayElement>
的'value'属性类型由父<ModelSpecification>
的'type'属性值控制。<ModelSpecification>
必须具有'value'属性或'numElements'属性,但不能同时具有两者。<ModelSpecification>
包含<ArrayElement>
,并且这些元素的数量仅限于该属性的值。所以我的问题是:
谢谢,
汤姆
答案 0 :(得分:3)
可能编写模式来验证给定的XML(稍作修改),但仅限于某些条件。也就是说,您的第三个项目符号点不能像您描述的那样在XML模式中定义(使用numElements值本身来限制ArrayElements的数量)。但是,如果您知道numElements只有某些值,则可以创建与每个选项对应的模式元素。如果numElements可能很大或可能会随着时间的推移而增长,那么这对您来说可能不是一个好选择。
我也同意numElements是多余的(类型也是如此)。但是我让他们完整了。
我想在输入之前向自己证明这一点,所以我实际上最终编写了整个架构。无论如何我都这样做了,我也可以传递它:)有两种编写XML的方法可以用这个模式进行验证。你担心它是人类可读的,我不知道你更喜欢哪个选项。 (为了空间的利益,我省略了Real和Bool类型)。
第一个选项跳过xsi:type并直接重命名<ModelSpecification>
元素(感谢替换组):
<Calculation xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Model />
<Simulation>
<OneValueIntegerModel name='intParam' type='integer' value='7'/>
<TwoValueIntegerModel name="intArrayParam" type="integer" numElements="2">
<ArrayElement value="5" />
<ArrayElement value="6" />
</TwoValueIntegerModel>
<OneValueStringModel name='scalarSelector' type='string' value='apple'/>
<ThreeValueStringModel name='arraySelector' type='string' numElements='3'>
<ArrayElement value='red'/>
<ArrayElement value='yellow'/>
<ArrayElement value='blue'/>
</ThreeValueStringModel>
<ReportVariable pathName='myUnit.Var1'/>
<ReportVariable pathName='myUnit.Var2(1)'/>
<ReportVariable pathName='myUnit.Var2(2)'/>
</Simulation>
</Calculation>
第二个选项保留名为<ModelSpecification>
的元素并使用xsi:type来声明它是哪种类型:
<Calculation xmlns="http://stackoverflow-sample" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Model />
<Simulation>
<ModelSpecification xsi:type="OneValueIntegerModel" name='intParam' type='integer' value='7'/>
<ModelSpecification xsi:type="TwoValueIntegerModel" name="intArrayParam" type="integer" numElements="2">
<ArrayElement value="5" />
<ArrayElement value="6" />
</ModelSpecification>
<ModelSpecification xsi:type="OneValueStringModel" name='scalarSelector' type='string' value='apple'/>
<ModelSpecification xsi:type="ThreeValueStringModel" name='arraySelector' type='string' numElements='3'>
<ArrayElement value='red'/>
<ArrayElement value='yellow'/>
<ArrayElement value='blue'/>
</ModelSpecification>
<ReportVariable pathName='myUnit.Var1'/>
<ReportVariable pathName='myUnit.Var2(1)'/>
<ReportVariable pathName='myUnit.Var2(2)'/>
</Simulation>
</Calculation>
可用于验证这两个选项的架构如下:
<xs:schema elementFormDefault="qualified"
targetNamespace="http://stackoverflow-sample"
xmlns="http://stackoverflow-sample"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Calculation">
<xs:complexType>
<xs:sequence>
<xs:element name="Model" />
<xs:element name="Simulation">
<xs:complexType>
<xs:sequence>
<xs:element ref="ModelSpecification" minOccurs="1" maxOccurs="unbounded" />
<xs:element name="ReportVariable" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="pathName" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ModelSpecification" type="ModelSpecification" abstract="true" />
<xs:complexType name="ModelSpecification" abstract="true">
<xs:attribute name="name" type="xs:token" use="required" />
<xs:attribute name="type" type="xs:QName" use="required" />
</xs:complexType>
<!--Integer Model-->
<xs:complexType name="IntegerArrayElement">
<xs:attribute name="value" type="xs:integer" use="required" />
</xs:complexType>
<xs:element name="OneValueIntegerModel" type="OneValueIntegerModel" substitutionGroup="ModelSpecification" />
<xs:complexType name="OneValueIntegerModel">
<xs:complexContent>
<xs:extension base="ModelSpecification">
<xs:attribute name="value" type="xs:integer" use="required" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="TwoValueIntegerModel" type="TwoValueIntegerModel" substitutionGroup="ModelSpecification" />
<xs:complexType name="TwoValueIntegerModel">
<xs:complexContent>
<xs:extension base="ModelSpecification">
<xs:sequence>
<xs:element name="ArrayElement" type="IntegerArrayElement" minOccurs="2" maxOccurs="2" />
</xs:sequence>
<xs:attribute name="numElements" type="xs:integer" use="required" fixed="2" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!--String Model-->
<xs:complexType name="StringArrayElement">
<xs:attribute name="value" type="xs:string" use="required" />
</xs:complexType>
<xs:element name="OneValueStringModel" substitutionGroup="ModelSpecification" />
<xs:complexType name="OneValueStringModel">
<xs:complexContent>
<xs:extension base="ModelSpecification">
<xs:attribute name="value" type="xs:string" use="required" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="ThreeValueStringModel" type="ThreeValueStringModel" substitutionGroup="ModelSpecification" />
<xs:complexType name="ThreeValueStringModel">
<xs:complexContent>
<xs:extension base="ModelSpecification">
<xs:sequence>
<xs:element name="ArrayElement" type="StringArrayElement" minOccurs="3" maxOccurs="3" />
</xs:sequence>
<xs:attribute name="numElements" type="xs:integer" use="required" fixed="3" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
答案 1 :(得分:1)
是的,XSD不支持您为该XML语法提出的[1,3]场景。对于方案2,您可以使用<xsd:choice>
和min / maxOccurs = 1。
您还可以将元素语法更改为不是类型变体并创建该验证。
如果您使用SAX解析器解析XML,则需要知道该结构并对其进行验证。所以,我认为这种情况下你可以放弃XSD验证。
但是,如果是其他人创建该XML文件,那么XSD可能非常方便,因为它可以在到达您的系统之前在外部进行验证。
答案 2 :(得分:1)
当type =“integer”时,不可能直接验证,值不能为“1.23”。您可以做的是首先将此XML转换为可以更严格验证的内容,或者以这种方式更改初始方案。
我认为属性“numElements”是一个冗余属性btw,因为你可以读取/反序列化并计算元素。
<ModelSpecification name="realParam">
<RealParam>1.234</RealParam>
</ModelSpecification>
<ModelSpecification name='intParam'>
<IntParam>7</IntParam>
</ModelSpecification>
<ModelSpecification name='realArrayParam'>
<Array>
<RealParam>1.2</RealParam>
<RealParam>2.1</RealParam>
</Array>
</ModelSpecification>