2010-05-05 10 views
8

. (Nota: No puedo cambiar la estructura del XML que recibo yo sólo soy capaz de cambiar la forma en que validarlo.)Esquema XML: ¿Puedo hacer que algunos de los valores de un atributo sean necesarios pero aún así permitir otros valores?

Digamos que puedo conseguir XML como esto:

<Address Field="Street" Value="123 Main"/> 
<Address Field="StreetPartTwo" Value="Unit B"/> 
<Address Field="State" Value="CO"/> 
<Address Field="Zip" Value="80020"/> 
<Address Field="SomeOtherCrazyValue" Value="Foo"/> 

I necesita crear un esquema XSD que valide que "Calle", "Estado" y "Zip" debe estar presente. Pero no me importa si están presentes "StreetPartTwo" y/o "SomeOtherCrazyValue".

Si supiera que única los tres me importa podrían incluirse (y que cada uno sólo se incluiría una vez), lo que podía hacer algo como esto:

<xs:element name="Address" type="addressType" maxOccurs="unbounded" minOccurs="3"/> 

<xs:complexType name="addressType"> 
    <xs:attribute name="Field" use="required"> 
    <xs:simpleType> 
     <xs:restriction base="xs:string"> 
     <xs:enumeration value="Street"/> 
     <xs:enumeration value="State"/> 
     <xs:enumeration value="Zip"/> 
     </xs:restriction> 
    </xs:simpleType> 
    </xs:attribute> 
</xs:complexType> 

Pero esto won' Trabajo con mi caso porque también puedo recibir esos otros elementos de Dirección (que también tienen atributos de "Campo") que no me importan.

Alguna idea de cómo puedo asegurar que las cosas que me importan estén presentes, pero también las otras cosas?

TIA! Sean

+0

No creo que su sugerencia trabajaría de todos modos, incluso si usted no tiene la posibilidad de tener los atributos SomeOtherCrazyValue. El motivo es que su esquema propuesto se declararía como válido, un documento XML que tenía 3 elementos '

', cada uno con un atributo Street. (Sin código postal, sin estado). Su esquema no se ocupará de eso. – Cheeso

+0

Hmm, eso es cierto. En mi dominio, otros factores evitarían que esto sucediera. Pero en el caso general definitivamente podría. Agregaré una nota en la pregunta original sobre esa parte. Por supuesto, mi pregunta real aún está abierta. Gracias Cheeso! – scrotty

Respuesta

6

No puede hacer la validación que busca, con solo XML Schema.

Según la "XML Schema Part 1: Structures" specification ...

Cuando dos o más partículas contenidas directa o indirectamente en los {partículas} de un grupo de modelo han nombrado idénticamente declaraciones de elementos como su {término}, las definiciones de tipos de esas declaraciones debe ser el mismo.

No es que no se puede construir un esquema que valide un documento correcto. Lo que significa es que no puede crear un esquema que no se pueda validar en algunos documentos incorrectos. Y cuando digo "incorrecto", me refiero a los documentos que infringen las restricciones que usted indicó en inglés.

Por ejemplo, suponga que tiene un documento que incluye tres elementos de la calle, así:

<Address Field="Street" Value="123 Main"/> 
<Address Field="Street" Value="456 Main"/> 
<Address Field="Street" Value="789 Main"/> 
<Address Field="SomeOtherCrazyValue" Value="Foo"/> 

De acuerdo con el esquema, ese documento es una dirección válida. Es posible agregar una restricción xs:unique a su esquema para que rechace tales documentos rotos. Pero incluso con un xs: único, la validación contra dicho esquema declararía que algunos otros documentos incorrectos son válidos, por ejemplo, un documento con tres elementos <Address>, cada uno de los cuales tiene un único atributo Field, pero ninguno de los cuales tiene Field="Zip".

De hecho, no es posible producir un esquema W3C XML que codifique formalmente sus restricciones establecidas. El elemento <xs:all>casi te lleva por aquí, pero se aplica solo a los elementos, no a los atributos. Y no se puede usar con una extensión, por lo que no se puede decir, en W3C XML Schema, "todos estos elementos en cualquier orden, más cualquier otro".


Para llevar a cabo la validación que busca, las opciones son:

  1. se basan en algo que no sea XML Schema,
  2. realizar la validación en varios pasos, utilizando el esquema XML para el primer paso y algo más para el segundo paso.

Para la primera opción, creo que podría utilizar Relax NG para hacerlo. La desventaja de esto es que no es un estándar y, por lo que yo sé, no es ampliamente compatible ni está creciendo. Sería como aprender gaélico para expresar un pensamiento. No hay nada de malo en gaélico, pero es una especie de callejón sin salida lingüística, y I think RelaxNG is, too.

Para la segunda opción, un enfoque sería para validar contra de su esquema como el primer paso, y luego, como segunda etapa:

A. aplicar una transformación XSL que convertiría <Address> elementos en elementos nombrados por el valor de su atributo de campo. La salida de esa transformación se vería así:

<root> 
    <Street Value="101 Bellavista Drive"/> 
    <State Value="Confusion"/> 
    <Zip Value="10101"/> 
</root> 

B. validar la salida de ese transformada con un esquema diferente, que es como la siguiente:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      elementFormDefault="qualified"> 
    <xs:element name="root"> 
    <xs:complexType> 
     <xs:all> 
     <xs:element maxOccurs="1" minOccurs="1" ref="Street" /> 
     <xs:element maxOccurs="1" minOccurs="1" ref="State" /> 
     <xs:element maxOccurs="1" minOccurs="1" ref="Zip" /> 
     </xs:all> 
    </xs:complexType> 
    </xs:element> 

    <xs:element name="Street"> 
    <xs:complexType> 
     <xs:attribute name="Value" use="required" type="xs:string"/> 
    </xs:complexType> 
    </xs:element> 
    <xs:element name="State"> 
    <xs:complexType> 
     <xs:attribute name="Value" use="required" type="xs:string"/> 
    </xs:complexType> 
    </xs:element> 
    <xs:element name="Zip"> 
    <xs:complexType> 
     <xs:attribute name="Value" use="required" type="xs:string"/> 
    </xs:complexType> 
    </xs:element> 

</xs:schema> 

lo que se necesita para extender ese esquema para manejar otros elementos como <SomeOtherCrazyValue> en la salida de la transformación. O bien, podría estructurar la transformación xsl para que simplemente no emita elementos que no sean uno de {State, Street, Zip}.

Para que quede claro, entiendo que no puede cambiar el XML que recibe. Este enfoque no requeriría eso. Solo usa un enfoque de validación en dos pasos funky. Una vez que se complete el segundo paso de validación, puede descartar el resultado de la transformación.


EDITAR - En realidad, Sean, pensando en esto de nuevo, es posible que utilices el paso B. Supongamos transformar su XSL Elimina del documento sólo <Address> elementos que no tienen Estado, Calle o Código Postal para el valor de atributo de campo. En otras palabras, no habría <Address Field="SomeOtherCrazyValue"...>. El resultado de esa transformación podría validarse con su esquema, utilizando maxOccurs = "3", minOccurs = "3" y xs: unique.

+0

Gran respuesta, Cheeso. ¡Gracias! Lo que escribes es lo que sospechaba. Tendré que pensar en tu sugerencia de usar una transformación xsl (o RelaxNG/Gaelic; ^). Mi idea inicial fue que, dado que desajuste el xml de los pojos de Java, podría escribir una rutina simple que los inspeccione en ese momento. Pero, por supuesto, si hubiera sido posible, hacerlo todo en una sola xsd hubiera sido preferible. ¡Gracias de nuevo! Sean – scrotty

+0

no hay problema - en realidad creo que RelaxNG es la opción "gaélica". Hacer la Transformación XSL es una alternativa para aprender Gaélico, simplemente trabajo extra en un idioma que ya conoces. – Cheeso

+0

ps: Sé que alguien va a pisotearme por comparar RelaxNG con gaélico. – Cheeso

0

Tengo el mismo problema que tú, pero superado con un truco.

Solicitud XML

<request> 
    <url>Abcd</url> 
    <base-url>XXXXX/</base-url> 
    <args src="url"> 
     <arg name="languageCode">NL</arg> 
     <arg name="version">1</arg> 
     <arg name="offerId">10</arg> 
     <arg name="rewardId">1234</arg> 
    </args> 
</request> 

Ahora usa un XSLT y convertirlo,

código XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" 
indent="yes" /> 
<xsl:template match="@* | node()"> 
<xsl:copy> 
<xsl:apply-templates select="@* | node()" /> 
</xsl:copy> 
</xsl:template> 
<xsl:template match="arg"> 
<xsl:element name="{@name}"> 
<xsl:apply-templates /> 
</xsl:element> 
</xsl:template> 
</xsl:stylesheet> 

convertido en el XML

<?xml version="1.0" encoding="UTF-8"?> 
<request> 

    <url>abcd</url> 
    <base-url>XXXXXXX</base-url> 
    <args src="url"> 
     <languageCode>NL</languageCode> 
     <version>1</version> 
     <offerId>10</offerId> 
     <rewardId>1234</rewardId> 
    </args> 
</request> 

Ahora aplique XSD

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="request"> 
    <xs:complexType> 
     <xs:sequence> 
     <xs:element type="xs:string" name="url"/> 
     <xs:element type="xs:string" name="base-url"/> 
     <xs:element name="args" maxOccurs="unbounded" minOccurs="0"> 
      <xs:complexType mixed="true"> 
      <xs:sequence> 
       <xs:element type="xs:string" name="languageCode" minOccurs="0"/> 
       <xs:element type="xs:string" name="version" minOccurs="0"/> 
       <xs:element type="xs:string" name="offerId" minOccurs="1"/> 
       <xs:element type="xs:string" name="rewardId" minOccurs="1"/> 
      </xs:sequence> 
      <xs:attribute type="xs:string" name="src" use="optional"/> 
      </xs:complexType> 
     </xs:element> 
     </xs:sequence> 
    </xs:complexType> 
    </xs:element> 
</xs:schema> 
Cuestiones relacionadas