6

任意の順序で許可される要素のリストを取得しようとしています。一部の要素は必須 (最小 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>
4

3 に答える 3

11

私はちょうど同じ問題に遭遇し、彼らがXHTML XSDで何をしたかを見ました。内部の同じ状況head:titleが必須で、baseオプションであり、任意の数のscriptstylemetalinkおよび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})

したがって、技術的には機能します。

ただし、これには、必須要素とオプション要素のすべての可能な順列 (その他のものを間に挟んで) を の中に入れる必要がありますchoicen要素の場合、それは子n!ノードです。したがって、XHTML のn=2場合、最終的には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
于 2013-02-12T22:35:11.500 に答える
5

choiceその子要素の 1 つだけが XML グラフに存在することを許可します。sequence要素が常に同じ順序である場合に使用したいようです。順序が可変の場合は、含まれているリスト要素にあるallすべての要素を使用してラップする必要があります。これは、その子要素の 1 回または 0 回の出現のみが許可されるためです。maxOccurs="unbounded"all

編集:

また、選択要素から minOccurs と 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...>
于 2012-06-05T18:16:29.827 に答える
2

Basically, don't do that when using XSD. It is not designed for a use case like this.

You can validate with RelaxNG instead, using its unordered operation, or if you have a partner who requires an XSD then enforce an arbitrary order.

The schema for atom feeds given in RFC4287 uses RelaxNG for this reason:

   atomFeed =
      element atom:feed {
         atomCommonAttributes,
         (atomAuthor*
          & atomCategory*
          & atomContributor*
          & atomGenerator?
          & atomIcon?
          & atomId
          & atomLink*
          & atomLogo?
          & atomRights?
          & atomSubtitle?
          & atomTitle
          & atomUpdated
          & extensionElement*),
         atomEntry*
      }

See Principles of XML design: When the order of XML elements matters for further discussion of when to enforce order in XML

于 2016-04-06T10:52:11.277 に答える