xml - esquema - interpretar xsd
Esquema XML: elemento raíz (6)
¿Cómo indica este código que es el elemento raíz?
John, ese esquema acaba de definir todos los elementos y cualquiera de ellos se puede elegir como un elemento raíz. Si intenta generar un xml de muestra desde cualquier herramienta como Altova XML Spy o su tipo, podrá elegir un elemento para ser el elemento raíz.
Entonces cualquiera de esos elementos puede ser la raíz.
Para evitar la ambigüedad, use un elemento definido globalmente.
La siguiente publicación pregunta cómo indicar que un elemento es el elemento raíz en un esquema XML:
¿Es posible definir un elemento raíz en un documento XML usando Schema?
He seguido el tutorial de w3schools sobre XML Schema, pero todavía hay algo que no está claro. Considere el esquema de ejemplo 2 de http://www.w3schools.com/schema/schema_example.asp (reproducido a continuación para mayor comodidad). ¿Cómo indica este código que <shiporder>
es el elemento raíz? ¿No es el ejemplo que dice que todos los elementos son válidos como elementos raíz?
------------------ instancia ------------------------------- ---
<?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>
----------------------- esquema ------------------------
<?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>
Desde mi punto de vista, un esquema XML debería hacer dos cosas:
- definir qué puede ocurrir dentro de cada nodo
- definir dónde se puede colocar cada nodo
Y parece que el ejemplo falla en el # 2. ¿Alguna sugerencia?
No todos están de acuerdo, pero el hecho de que XML Schema no pueda especificar un elemento raíz es por diseño. El pensamiento es que si una <invoice>
es válida cuando es la única cosa en un documento, entonces es igualmente válida si está contenida en otra cosa. La idea es que el contenido sea reutilizable y no se le debe permitir evitar que alguien use contenido válido como parte de algo más grande.
(El hecho de que ID e IDREF tengan el alcance de un documento va en contra de esta política, pero luego el lenguaje fue diseñado por un comité bastante grande).
Sí, tiene usted razón. el xsd debería ser:
<?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>
como ve, ahora solo hay un xs:element
y ese es el único que puede ser un elemento raíz válido :)
La desventaja de muchos elementos globales es que todos podrían usarse como elementos raíz para documentos. La ventaja es entonces que puede usar el elemento cuando defina nuevos tipos que garantizarán que el espacio de nombres de los elementos secundarios coincidan con los del tipo padre.
He cambiado de pensar que solo debería haber un elemento global para que todos los tipos complejos tengan un elemento global.
Según el ejemplo que proporcionó, es posible encontrar el único elemento raíz.
Puede obtener una lista de elementos globales y luego obtener una lista de elementos anidados a los que se hace referencia en complexType bajo la secuencia xs: node, por lo tanto, el elemento raíz es el de la lista de elementos globales pero no de la lista de elementos anidados.
Lo he hecho utilizando la clase XmlSchemaSet en .NET. Aquí está el fragmento de código:
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));
El método de extensión 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;
}
}
}
}
Pero todavía hay problemas para la xsd general cuando se utiliza este enfoque. Por ejemplo, en DotNetConfig.xsd que Visual Studio usa para el archivo de configuración, el elemento raíz se define de la siguiente manera:
<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>
Todavía no he encontrado una solución completa para tratar todo tipo de esquemas. Continuaré por eso.
Hasta donde yo sé, cualquier elemento definido globalmente se puede usar como elemento raíz, y XML Schema no tiene una noción para especificar lo que se supone que es el elemento raíz.
Sin embargo, puede solucionar esto diseñando bien su Esquema XML, de modo que solo haya un elemento definido globalmente, entonces solo este elemento es válido como elemento raíz.
Un ejemplo de esto se puede encontrar en W3Schools (encabezado Uso de tipos con nombre ) Este ejemplo solo tiene un elemento definido globalmente y, por lo tanto, solo un elemento raíz posible.