2013-05-10 1 views
1

J'ai cherché ceci, mais je ne trouve pas de solution à mon problème, alors ne jetez pas cette question.La clé XSD ne se trouve pas dans l'élément racine et les clés complexes

Nous avons un service avec une configuration XML très complexe qui est décrite par XSD. Il y a beaucoup de règles qui doivent être respectées pour que les choses se passent bien. XSD décrit la structure de la configuration, mais pas les règles, que nous devons faire maintenant. Après avoir créé quelques règles globales, nous devons faire quelques plus complexes maintenant et nous avons rencontré un problème. Il semble que le validateur utilise uniquement key/keyref/unique de l'élément racine. J'ai créé petit XSD et le fichier XML pour illustrer le fait que:

XSD:

<?xml version="1.0" encoding="utf-8"?> 
<xs:schema targetNamespace="http://test.org/XMLSchema.xsd" 
    elementFormDefault="qualified" 
    xmlns="http://test.org/XMLSchema.xsd" 
    xmlns:t="http://test.org/XMLSchema.xsd" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="Orders" type="t:OrdersList"> 
    <xs:key name="OrderNo"> 
     <xs:selector xpath="./t:Order" /> 
     <xs:field xpath="@Number" /> 
    </xs:key> 
    </xs:element> 

    <xs:complexType name="OrdersList"> 
    <xs:sequence> 
     <xs:element minOccurs="0" maxOccurs="unbounded" name="Order" nillable="false" type="t:Order" /> 
    </xs:sequence> 
    </xs:complexType> 

    <xs:complexType name="Order"> 
    <xs:sequence> 
     <xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList" /> 
    </xs:sequence> 
    <xs:attribute name="Number" use="optional" type="xs:string" /> 
    <xs:attribute name="ClientId" use="optional" type="xs:int" /> 
    </xs:complexType> 

    <xs:complexType name="OrdersLinesList"> 
    <xs:sequence> 
     <xs:element minOccurs="0" maxOccurs="unbounded" name="Line" nillable="false" type="t:OrderLine"> 
     <!-- THE PROBLEM --> 
     <xs:key name="LineNoKey"> 
      <xs:selector xpath="./t:Line" /> 
      <xs:field xpath="@LineNumber" /> 
     </xs:key> 
     </xs:element> 
    </xs:sequence> 
    </xs:complexType> 

    <xs:complexType name="OrderLine"> 
    <xs:attribute name="LineNumber" use="optional" type="xs:string" /> 
    <xs:attribute name="ProductId" use="optional" type="xs:int" /> 
    <xs:attribute name="Amount" use="optional" type="xs:decimal" /> 
    </xs:complexType> 
</xs:schema> 

XML:

<?xml version="1.0" encoding="utf-8"?> 
<Orders xmlns="http://test.org/XMLSchema.xsd"> 
    <Order Number="0001/5/13" ClientId="123"> 
    <Lines> 
     <Line LineNumber="1" ProductId="123" Amount="4" /> 
     <Line LineNumber="2" ProductId="124" Amount="4" /> 
    </Lines> 
    </Order> 
    <Order Number="0002/5/13" ClientId="123"> 
    <Lines> 
     <Line LineNumber="1" ProductId="123" Amount="4" /> 
     <!-- Duplicate number - it DOES validate as expected. --> 
     <Line LineNumber="1" ProductId="124" Amount="4" /> 
    </Lines> 
    </Order> 
    <!-- Duplicate number - it doesn't validate as expected. --> 
    <Order Number="0002/5/13" ClientId="123"> 
    <Lines> 
     <Line LineNumber="1" ProductId="123" Amount="4" /> 
     <Line LineNumber="2" ProductId="124" Amount="4" /> 
    </Lines> 
    </Order> 
</Orders> 

J'ai quelques questions que je ne peux trouver aucune réponse sensée:

  1. Comment résoudre ce qui précède. LineNumber doit être unique, mais uniquement dans Order/Lines.
  2. Est-il possible de permettre à keyref de contenir une valeur virtuelle non existante (notre service utilise des éléments prédéfinis, par exemple), ceux qui sont personnalisés en XML pour permettre l'extension des fonctionnalités, mais dans la plupart des cas, ones)
  3. Existe-t-il un moyen de déterminer si la liste d'éléments dans une balise (quelque chose comme les lignes ci-dessus) a au moins une balise avec un attribut défini à une certaine valeur. Un bon exemple serait de le décrire comme une liste de tables avec des noms uniques, qui a une liste de colonnes avec des noms uniques et au moins une des colonnes est une clé primaire.

Répondre

1

C'est la contrainte corrigée des lignes/ligne:

<xs:complexType name="Order"> 
    <xs:sequence> 
     <xs:element minOccurs="1" maxOccurs="1" name="Lines" nillable="false" type="t:OrdersLinesList"> 
      <!-- THE PROBLEM SOLVED --> 
      <xs:key name="LineNoKey"> 
       <xs:selector xpath="t:Line"/> 
       <xs:field xpath="@LineNumber"/> 
      </xs:key>    
     </xs:element> 
    </xs:sequence> 
    <xs:attribute name="Number" use="optional" type="xs:string"/> 
    <xs:attribute name="ClientId" use="optional" type="xs:int"/> 
</xs:complexType> 

Si aide toujours si vous pouvez visualiser vos contraintes, de comprendre la portée qu'ils agissent sur:

Le schéma correct:

enter image description here

par rapport à l'original:

enter image description here

Vous pouvez voir que le sélecteur ancré dans l'élément ligne recherche encore une autre ligne (./t:Line); et même si vous corrigez le sélecteur, il correspondra toujours au maximum à un attribut. L'idée d'une clé est que le sélecteur doit correspondre à un ensemble de nœuds parmi lesquels le champ doit être présent et unique.

Ce qui précède devrait prendre soin de 1.

  1. n °
  2. Non basé sur un attribut. Pour coller avec votre parallèle, pour XSD 1.0 J'appliquerais probablement un élément appelé PrimaryKey, qui devrait contenir une ou plusieurs références aux noms des autres colonnes; comme si au lieu d'utiliser la clause de contrainte PRIMARY KEY dans une définition de colonne, je voudrais imposer l'utilisation de la même au niveau de la table.
+0

Merci l'homme ... Je n'ai pas pensé à ça ... Quel logiciel avez-vous utilisé pour visualiser cela? – dr4cul4

+0

@ dr4cul4, j'ai utilisé celui que nous développons - voir mon profil. –

Questions connexes