2009-05-21 28 views
13

Estoy tratando de definir algunas restricciones de clave externa en un esquema XML utilizando las definiciones xs: key y xs: keyref. Quiero que la estructura del documento para ser jerárquica de la siguiente manera:Tecla XSD/keyref: estructura de clave jerárquica

<?xml version="1.0" encoding="UTF-8"?> 
<tns:root xmlns:tns="http://www.example.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/ SampleSchema.xsd "> 
    <parent parentKey="parent1"> 
    <child childKey="child1"/> 
    <child childKey="child2"/> 
    </parent> 
    <parent parentKey="parent2"> 
    <child childKey="child1"/> 
    <child childKey="child2"/> 
    </parent> 
    <referrer parentRef="parent1" childRef="child2"/> 
</tns:root> 

A cada padre tiene una clave (a nivel mundial) único, definido por parentKey. Cada elemento secundario tiene la clave definida por childKey, , pero childKey solo es único dentro del alcance de su elemento primario contenedor.

Luego hay una lista de referencias con referencias de claves externas a un padre y un hijo en particular.

Soy capaz de definir las claves como quiero, simplemente poniéndolas en el elemento correcto: la restricción parentKey en el elemento raíz y la restricción childKey en el elemento padre. También puedo definir keyref to parentKey sin dificultad.

Los problemas surgen al tratar de definir un keyref a childKey. Traté de definir un keyref simple en el elemento raíz para childKey, pero eso no funciona, ya que no veo manera de seleccionar solo los elementos secundarios bajo el subárbol padre apropiado. (El validador de Eclipse, al menos, siempre simplemente valida el contenido del último subárbol padre en el documento ...).

Luego trató de definir una clave compuesta (de raíz), con:

  • selector = matriz
  • campo = @parentKey
  • campo = niño/@ childKey

Este falla si hay más de un hijo definido bajo el padre. Ese es el comportamiento correcto basado en XSD 1.1 spec, sección 3.11.4, elemento 3, que establece que la clave tiene que coincidir como máximo con un nodo por definición de campo.

Solo para reiterar: si forzo a childKeys a ser globalmente único, esto es fácil de implementar; la dificultad está en hacer referencia localmente childKeys únicos.

¿Alguno de los maestros de XSD tiene una idea?

Como referencia, aquí hay una muestra de XSD, con un fallido childKey keyref comentada:

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/" xmlns:tns="http://www.example.org/" elementFormDefault="unqualified"> 

    <element name="root"> 
     <complexType> 
      <sequence> 
       <element name="parent" maxOccurs="unbounded" minOccurs="1"> 
        <complexType> 
         <sequence> 
          <element name="child" maxOccurs="unbounded" minOccurs="1"> 
           <complexType> 
            <attribute name="childKey" type="string" use="required"/> 
           </complexType> 
          </element> 
         </sequence> 
         <attribute name="parentKey" type="string" use="required"/> 
        </complexType> 
        <key name="childKeyDef"> 
         <selector xpath="child"/> 
         <field xpath="@childKey"/> 
        </key> 
       </element> 
       <element name="referrer" maxOccurs="unbounded" minOccurs="1"> 
        <complexType> 
         <attribute name="parentRef" type="string"/> 
         <attribute name="childRef" type="string"/> 
        </complexType> 
       </element> 
      </sequence> 
     </complexType> 
     <key name="parentKeyDef"> 
      <selector xpath="parent"/> 
      <field xpath="@parentKey"/> 
     </key> 
     <keyref name="parentKeyRef" refer="tns:parentKeyDef"> 
      <selector xpath="referrers"/> 
      <field xpath="@parentRef"/> 
     </keyref> 
<!--  <keyref name="childKeyRef" refer="tns:childKeyDef">--> 
<!--   <selector xpath="referrers"/>--> 
<!--   <field xpath="@childRef"/>--> 
<!--  </keyref>--> 
    </element> 
</schema> 
+1

Hola Aron, DID a encontrar una solución para este problema? También estoy atrapado con un problema similar. (No puedo cambiar mi xml). – Rahul

+1

Me temo que no, terminamos moviéndonos a un formato no XML para el intercambio de datos, haciendo que la pregunta sea discutible. – Aron

Respuesta

2

¿Qué tal en referencia al padre del niño? Incluso si muchos niños, sólo habrá uno de los padres, y la combinación de la (padres, hijos) crea una clave única a nivel mundial, a pesar de que la tecla de niños sólo es única dentro de su matriz:

<key name="childKeyDef"> 
    <selector xpath="child"/> 
    <field xpath="@childKey"/> 
    <field xpath="../@parentKey"/> 
    </key> 

Esto no funciona en xmllint, aunque la especificación no parece desautorizar explícitamente esto para los campos, solo para los selectores: 3.11.4, (2) dice que el selector no puede ser un antecesor (solo puede ser el nodo contextual o descendientes).

Ah, aquí está el clavo en el ataúd (mirando la sintaxis específica): las expresiones XPath permitidas son muy limitadas, y simplemente no incluyen "..."http://www.w3.org/TR/xmlschema-1/#c-fields-xpaths

Así que, lo siento, esto no responde a su pregunta, pero tal vez le dará algunas ideas.

+1

Sí; Lo intenté yo mismo e hice el mismo descubrimiento acerca de las estrictas limitaciones en las expresiones de selector y campo xpath. Una buena idea en teoría, sin embargo. ¡Gracias por los esfuerzos! – Aron

+0

Conjeturo que al combinar esta restricción, junto con la otra restricción que encontraste (para que xpath se refiera a un solo nodo), hay una prueba de que lo que quieres hacer es imposible en XSD. Apuesto a que la prueba (si es uno) es muy simple, pero no puedo verlo del todo. – 13ren

1

Una solución fea es cambiar su formato XML, por lo que el parentKey se incluye en cada niño , como esto:?

<parent> 
    <child parentKey="parent1" childKey="child1"/> 
    <child parentKey="parent1" childKey="child2"/> 
</parent> 

creo que su situación es muy legítimo, y yo esperaría que haya una manera de hacer esto - por qué no probar la lista de correo xml-dev se ha convertido en ruidoso última vez que revisé, pero algunos de los creadores de xml seguían saliendo por ahí.

+0

Sí, eso sería una posibilidad, pero creo que causa más problemas de los que resuelve ... como dices, feo. Mi diseño se ha alejado de esta estructura por razones externas, por lo que es más un ejercicio académico en este momento, pero tal vez le daré una oportunidad a la lista. ¡Gracias por la idea! – Aron

0

Tuve una pregunta similar: XML Schema Key with multiple fields

Decidí que el mejor enfoque para mí era reordenar el XML para permitir que el alcance fuera determinado por localidad en lugar de aplicar una clave con dos campos.

En su escenario, si mueve la referencia en el elemento primario, esto permitirá que el alcance se configure para hacer referencia al elemento secundario apropiado. Luego, haría que el elemento referente haga referencia al alcance externo del elemento al que necesita hacer referencia.

Es un poco difícil determinar si esta es una solución aceptable porque su problema parece ser un poco abstracto. En mi problema, descrito en mi pregunta, estaba tratando con preguntas, respuestas y respuestas de los usuarios. Originalmente estaba tratando de validar si la respuesta de un usuario era en realidad una respuesta válida; mi primer enfoque involucró la misma técnica que estás usando. Mi solución final consistió en mover la respuesta dentro de la pregunta y luego referirme al usuario.

Mi XML ANTES:

<?xml version="1.0" encoding="utf-8"?> 
<survey> 
    <user id="bob"> 
    <response questionIdRef="q101">yes</response> 
    <response questionIdRef="q102">white</response> 
    </user> 
    <user id="jane"> 
    <response questionIdRef="q101">no</response> 
    <response questionIdRef="q102">blue</response> 
    </user> 
    <question id="q101"> 
    <text>Do you like the color red?</text> 
    <answer>yes</answer> 
    <answer>no</answer> 
    </question> 
    <question id="q102"> 
    <text>What is your favorite color?</text> 
    <answer>red</answer> 
    <answer>blue</answer> 
    <answer>white</answer> 
    <answer>yellow</answer> 
    </question> 
</survey> 

Mi XML DESPUÉS:

<?xml version="1.0" encoding="utf-8"?> 
<survey> 
    <user id="bob" /> 
    <user id="jane" /> 
    <question id="q101"> 
    <text>Do you like the color red?</text> 
    <answer>yes</answer> 
    <answer>no</answer> 
    <response userIdRef="bob">yes</response> 
    <response userIdRef="jane">no</response> 
    </question> 
    <question id="q102"> 
    <text>What is your favorite color?</text> 
    <answer>red</answer> 
    <answer>blue</answer> 
    <answer>white</answer> 
    <answer>yellow</answer> 
    <response userIdRef="bob">white</response> 
    <response userIdRef="jane">blue</response> 
    </question> 
</survey> 
Cuestiones relacionadas