Подтвердить что ты не робот

XML-схема: корневой элемент

В следующем сообщении спрашивается, как указать, что элемент является корневым элементом в XML-схема:

Можно ли определить корневой элемент в XML-документе с помощью схемы?

Я следил за учебником w3schools по XML Schema, но что-то до сих пор неясно. Рассмотрим пример схемы 2 из http://www.w3schools.com/schema/schema_example.asp (воспроизводится ниже для удобства). Как этот код указывает, что <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-схема должна делать две вещи:

  • определить, что может произойти внутри каждого node
  • определить, где можно разместить node

И похоже, что пример не работает на # 2. Любые предложения?

4b9b3361

Ответ 1

Насколько я знаю, любой глобально определенный элемент может использоваться как корневой элемент, а XML-схема не имеет понятия для указания того, каким должен быть корневой элемент.

Однако вы можете обойти это, хорошо спроектировав XML-схему, так что есть только один глобально определенный элемент - тогда только этот элемент действителен как корневой элемент.

Пример этого можно найти в W3Schools (заголовок Использование именованных типов) Этот пример имеет только один глобально определенный элемент и, следовательно, только один возможный корневой элемент.

Ответ 2

Не все согласны с этим, но тот факт, что XML Schema не может указать корневой элемент, - это дизайн. Мысль заключается в том, что если <invoice> действителен, когда это единственное в документе, то оно равнозначно, если оно содержится в чем-то другом. Идея состоит в том, что контент должен быть повторно использован, и вам не следует позволять помешать кому-либо использовать действительный контент как часть чего-то большего.

(Тот факт, что ID и IDREF привязаны к документу, скорее противоречит этой политике, но тогда язык был разработан довольно крупным комитетом.)

Ответ 3

да, вы правы. 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, и это единственный, который может быть допустимым корневым элементом:)

Ответ 4

Недостатком множества глобальных элементов является то, что все они могут использоваться как корневые элементы для документов. Преимущество заключается в том, что вы можете использовать этот элемент при определении новых типов, которые гарантируют, что пространство имен дочерних элементов соответствует типу родительского типа.

Я передумал, что должен быть только один глобальный элемент, чтобы все сложные типы имели глобальный элемент.

Ответ 5

Как этот код указывает, что является корневым элементом?

Джон, Эта схема просто определила все элементы, и любой из них можно выбрать в качестве корневого элемента. Если вы попытаетесь создать образец xml из любого инструмента, например Altova XML Spy или его вида, вы сможете выбрать элемент как корневой элемент.

Таким образом, любой из этих элементов может быть корнем.

Чтобы избежать двусмысленности, используйте один глобально определенный элемент.

Ответ 6

На основании приведенного вами примера можно найти единственный корневой элемент.

Вы можете получить список глобальных элементов, а затем получить список вложенных элементов, на которые ссылается в complexType в последовательности node xs:, таким образом, корневой элемент является тем, который указан в списке глобальных элементов, но не в списке вложенных элементов.

Я сделал это, используя класс XmlSchemaSet в .NET. Вот фрагмент кода:

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. Например, в DotNetConfig.xsd, который использует Visual Studio для файла конфигурации, корневой элемент определяется ниже:

  <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>

Я не нашел полного решения для решения всех видов схем. Будет продолжаться.