我正在尝试获得任何顺序允许的元素列表。有些元素是必需的(最小为1,最大为1),有些是可选的,最多为1,有些是可选的任何数字。这就是我所拥有的并且XSD是有效的,但是当我去验证XML时,我试图实现的规则没有被强制执行。例如,不需要id。
<xsd:complexType name="feedType">
<xsd:annotation>
<xsd:documentation>
The Atom feed construct is defined in section 4.1.1 of the format spec.
</xsd:documentation>
</xsd:annotation>
<xsd:choice minOccurs="3" maxOccurs="unbounded">
<xsd:element name="author" type="atom:personType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="category" type="atom:categoryType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="contributor" type="atom:personType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="generator" type="atom:generatorType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="icon" type="atom:iconType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="id" type="atom:idType" minOccurs="1" maxOccurs="1"/>
<xsd:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="logo" type="atom:logoType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="rights" type="atom:textType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="subtitle" type="atom:textType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="title" type="atom:textType" minOccurs="1" maxOccurs="1"/>
<xsd:element name="updated" type="atom:dateTimeType" minOccurs="1" maxOccurs="1"/>
<xsd:element name="entry" type="atom:entryType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
<xsd:attributeGroup ref="atom:commonAttributes"/>
</xsd:complexType>
答案 0 :(得分:10)
我遇到了同样的问题,看看他们在XHTML XSD中做了些什么。 head
内部的情况相同:title
是必需的,base
是可选的,然后有script
,style
,meta
的任意数量,link
和object
元素允许。
以下是他们所做的事情:首先,他们对可能出现多次的可选元素进行了分组:
<xs:group name="head.misc">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="script"/>
<xs:element ref="style"/>
<xs:element ref="meta"/>
<xs:element ref="link"/>
<xs:element ref="object"/>
</xs:choice>
</xs:sequence>
</xs:group>
然后他们在实际的head
定义中引用了这个组:
<xs:sequence>
<xs:group ref="head.misc"/>
<xs:choice>
<xs:sequence>
<xs:element ref="title"/>
<xs:group ref="head.misc"/>
<xs:sequence minOccurs="0">
<xs:element ref="base"/>
<xs:group ref="head.misc"/>
</xs:sequence>
</xs:sequence>
<xs:sequence>
<xs:element ref="base"/>
<xs:group ref="head.misc"/>
<xs:element ref="title"/>
<xs:group ref="head.misc"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
这有点棘手。写成类似正则表达式的伪代码,上面看起来像这样:
misc=(script|style|meta|link|object)*
head=${misc}(title${misc}(base${misc})?|base${misc}title${misc})
所以,从技术上讲它是有效的。
但是,这需要在choice
内放置强制和可选元素的所有可能排列(其中包含misc内容)。使用n
个元素,即n!
个子节点。因此,对于n=2
的XHTML,他们最终得到n!=2
。对于n=8
的情况,它将是n!=40320
。
FWIW,这是生成XSD的算法:
result = '<xs:group name="misc"><xs:sequence><xs:choice minOccurs="0" maxOccurs="unbounded">'
forall(optionalArbitraryCountElements as element)
result += '<xs:element ref="' + element.name + '"/>'
result += '</xs:choice></xs:sequence></xs:group>'
result += '<xs:complexType name="feedType"><xs:sequence><xs:group ref="misc"/><xs:choice>'
permutations = getAllPermutations(mandatoryElements + optionalOnceElements)
foreach (permutations as p)
result += '<xs:sequence>'
foreach (p as element)
if (element.isOptional)
result += '<xs:sequence minOccurs="0">'
result += '<xs:element ref="' + element.name + '"/><xs:group ref="misc"/>'
if (element.isOptional)
result += '</xs:sequence>'
result += '</xs:sequence>'
result += '</xs:choice></xs:sequence></xs:complexType>'
return result
答案 1 :(得分:5)
choice
仅允许其子元素之一出现在XML图中。如果您的元素始终处于相同的顺序,您似乎希望使用sequence
。如果顺序是可变的,那么您应该使用all
并将包含maxOccurs="unbounded"
的所有元素包含在包含列表元素中,因为all
仅允许其子元素出现1或0次。
编辑:
你应该删除minOccurs&amp;来自choice元素的maxOccurs。这只允许您强制执行3个选项,但不允许您指定它们的选择(包括多次重复相同的元素)。我不知道你究竟要强制执行什么,但不会以这种方式有效执行。
编辑2:
您可以按如下方式创建列表包装器(以link元素为例):
<xs:element name="linkList" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
并在xml文档中(例如)将链接元素嵌套在linkList中:
旧:
<other elements...>
<id>...</id>
<link>...</link>
<link>...</link>
<logo>...</logo>
<other elements...>
新:
<other elements...>
<id>...</id>
<linkList>
<link>...</link>
<link>...</link>
</linkList>
<logo>...</logo>
<other elements...>
答案 2 :(得分:1)
基本上,使用XSD时不要这样做。它不是为这样的用例设计的。
您可以使用RelaxNG进行验证,使用其无序操作,或者如果您有需要XSD的合作伙伴,则执行任意订单。
RFC4287中给出的原子Feed的模式使用RelaxNG:
atomFeed =
element atom:feed {
atomCommonAttributes,
(atomAuthor*
& atomCategory*
& atomContributor*
& atomGenerator?
& atomIcon?
& atomId
& atomLink*
& atomLogo?
& atomRights?
& atomSubtitle?
& atomTitle
& atomUpdated
& extensionElement*),
atomEntry*
}
有关何时在XML中强制执行订单的进一步讨论,请参阅Principles of XML design: When the order of XML elements matters