web-dev-qa-db-ja.com

XMLスキーマ:ルート要素

次の投稿では、要素がXMLスキーマのルート要素であることを示す方法を尋ねています。

スキーマを使用してXML文書にルート要素を定義することは可能ですか?

私はXMLスキーマに関するw3schoolsチュートリアルに従いましたが、まだはっきりしていません。 http://www.w3schools.com/schema/schema_example.asp (便宜上、以下に再現)のスキーマ2の例を考えてみましょう。このコードはどのように<shiporder>はルート要素ですか?この例では、すべての要素がルート要素として有効であると言っていませんか?

------------------インスタンス------------------------------- ---

<?xml version="1.0" encoding="ISO-8859-1"?>

<shiporder orderid="889923"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="shiporder.xsd">
  <orderperson>John Smith</orderperson>
  <shipto>
    <name>Ola Nordmann</name>
    <address>Langgt 23</address>
    <city>4000 Stavanger</city>
    <country>Norway</country>
  </shipto>
  <item>
    <title>Empire Burlesque</title>
    <note>Special Edition</note>
    <quantity>1</quantity>
    <price>10.90</price>
  </item>
  <item>
    <title>Hide your heart</title>
    <quantity>1</xample saying that all elements are valid as root elements?quantity>
    <price>9.90</price>
  </item>
</shiporder> 

-----------------------スキーマ------------------------

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- definition of simple elements -->
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>

<!-- definition of attributes -->
<xs:attribute name="orderid" type="xs:string"/>

<!-- definition of complex elements -->
<xs:element name="shipto">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="name"/>
      <xs:element ref="address"/>
      <xs:element ref="city"/>
      <xs:element ref="country"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="item">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="title"/>
      <xs:element ref="note" minOccurs="0"/>
      <xs:element ref="quantity"/>
      <xs:element ref="price"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="shiporder">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="orderperson"/>
      <xs:element ref="shipto"/>
      <xs:element ref="item" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute ref="orderid" use="required"/>
  </xs:complexType>
</xs:element>

</xs:schema>

私の観点から、XMLスキーマは2つのことを行う必要があります。

  1. 各ノード内で何が起こるかを定義する
  2. 各ノードを配置できる場所を定義する

そして、例は#2で失敗したようです。助言がありますか?

55
johngoche9999

私の知る限り、すべてのglobally定義された要素はルート要素として使用でき、XML Schemaにはルート要素が何であるかを指定する概念がありません察するに。

ただし、XMLスキーマを適切に設計することにより、この問題を回避できます。そのため、グローバルに定義された要素は1つだけで、この要素のみがルート要素として有効です。

この例は W3Schools (見出し名前付き型の使用)にあります。この例にはグローバルに定義された要素が1つだけあります。したがって、可能なルート要素は1つだけです。

51
Anony-Mousse

誰もがそれに同意するわけではありませんが、XMLスキーマがルート要素を指定できないという事実は仕様によるものです。思考は、<invoice>は、ドキュメント内の唯一のものである場合に有効であり、他の何かに含まれている場合も同様に有効です。コンテンツは再利用可能でなければならず、誰かが有効なコンテンツをより大きなものの一部として使用するのを防ぐことは許されないという考えです。

(IDとIDREFがドキュメントにスコープされるという事実は、むしろこのポリシーに反します;しかし、言語はかなり大きな委員会によって設計されました。)

21
Michael Kay

はい、あなたは正しいです。 xsdは次のようになります。

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- definition of attributes -->
<xs:attribute name="orderid" type="xs:string"/>

<!-- definition of complex elements -->
<xs:complexType name="shiptoType">
  <xs:sequence>
    <xs:element name="name" type="xs:string" />
    <xs:element name="address" type="xs:string" />
    <xs:element name="city" type="xs:string" />
    <xs:element name="country" type="xs:string" />
  </xs:sequence>
</xs:complexType>

<xs:complexType name="itemType">
  <xs:sequence>
    <xs:element name="title" type="xs:string" />
    <xs:element name="note" minOccurs="0" type="xs:string" />
    <xs:element name="quantity" type="xs:string" />
    <xs:element name="price" type="xs:string" />
  </xs:sequence>
</xs:complexType>

<xs:element name="shiporder">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="orderperson" type="xs:string" />
      <xs:element name="shipto" type="shiptoType"/>
      <xs:element name="item" maxOccurs="unbounded" type="itemType"/>
    </xs:sequence>
    <xs:attribute ref="orderid" use="required"/>
  </xs:complexType>
</xs:element>

</xs:schema>

ご覧のとおり、今ではxs:element、そしてそれは有効なルート要素になり得る唯一のものです:)

16
davogotland

多くのグローバル要素の欠点は、すべてがドキュメントのルート要素として使用できることです。利点は、新しいタイプを定義するときに要素を使用できることです。これにより、子要素のネームスペースが親タイプのネームスペースと一致することが保証されます。

グローバル要素は1つだけである必要があるという考えから、すべての複合型にはグローバル要素が必要であるという考えに変わりました。

1
xmlDave

このコードは、それがルート要素であることをどのように示していますか?

ジョン、そのスキーマはすべての要素を定義したばかりで、それらのどれでもルート要素として選択できます。 Altova XML Spyなどのツールからサンプルxmlを生成しようとすると、ルート要素となる要素を選択できます。

したがって、これらの要素はどれもルートになります。

あいまいさを防ぐために、1つのグローバルに定義された要素を使用します。

0
Sunil

指定した例に基づいて、唯一のルート要素を見つけることができます。

グローバル要素のリストを取得してから、ノードxs:sequenceの下のcomplexTypeで参照されているネスト要素のリストを取得できます。したがって、ルート要素はグローバル要素リストにありますが、ネスト要素リストにはありません。

.NETのXmlSchemaSetクラスを使用してこれを実行しました。コードスニペットは次のとおりです。

var localSchema = schemaSet.Schemas().OfType<XmlSchema>().Where(x => !x.SourceUri.StartsWith("http")).ToList();

var globalComplexTypes = localSchema
.SelectMany(x => x.Elements.Values.OfType<XmlSchemaElement>())
.Where(x => x.ElementSchemaType is XmlSchemaComplexType)
.ToList();

var nestedTypes = globalComplexTypes.Select(x => x.ElementSchemaType)
.OfType<XmlSchemaComplexType>()
.Select(x => x.ContentTypeParticle)
.OfType<XmlSchemaGroupBase>()
.SelectMany(x => x.GetNestedTypes())
.ToList();

var rootElement= globalComplexTypes.Single(x => !nestedTypes.Select(y => y.ElementSchemaType.QualifiedName).Contains(x.SchemaTypeName));

拡張メソッドGetNestedTypes:

static IEnumerable<XmlSchemaElement> GetNestedTypes(this XmlSchemaGroupBase xmlSchemaGroupBase)
{
    if (xmlSchemaGroupBase != null)
    {
        foreach (var xmlSchemaObject in xmlSchemaGroupBase.Items)
        {
            var element = xmlSchemaObject as XmlSchemaElement;
            if (element != null)
                yield return element;
            else
            {
                var group = xmlSchemaObject as XmlSchemaGroupBase;
                if (group != null)
                    foreach (var item in group.GetNestedTypes())
                        yield return item;
            }
        }
    }
}

しかし、このアプローチを使用する場合、一般的なxsdにはまだ問題があります。たとえば、Visual Studioが構成ファイルに使用するDotNetConfig.xsdでは、ルート要素は次のように定義されます。

  <xs:element name="configuration">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:any namespace="##any" processContents="lax" />
      </xs:choice>
      <xs:anyAttribute namespace="http://schemas.Microsoft.com/XML-Document-Transform" processContents="strict"/>
    </xs:complexType>
  </xs:element>

あらゆる種類のスキーマを処理する完全なソリューションはまだ見つかりませんでした。それのために続けます。

0
Johnny Qian