2017-10-02 2 views
4

Suite à certains didacticiels existants, j'ai créé un script Perl ci-dessous pour générer du code XML à partir de xsd.XML :: Compiler pour générer un exemple de code XML à partir d'un schéma avec énumération et choix

Script:

#!/opt/perl/bin/perl -w 
use warnings; 
use strict; 
use XML::Compile::Schema; 
use XML::LibXML::Reader; 
use XML::Compile::Util qw/pack_type/; 

my $in_qfn = $ARGV[0]; 
my $out_qfn = $ARGV[1]; 

open (OUT, ">$out_qfn") || die "Unable to create output file: $out_qfn\n"; 

# Generate the hash of xml 
my $schema = XML::Compile::Schema->new($in_qfn); 
my $type = pack_type 'urn:testsample','Document'; 
my $data = $schema->template('PERL', $type); 
$data =~ s/#.*//g; 
$data =~ s/\s*//g; 
$data = eval($data); 

# Print the xml 
my $doc = XML::LibXML::Document->new('1.0','UTF-8'); 
my $write = $schema->compile(WRITER=>$type); 
my $xml = $write->($doc,$data); 
$doc->setDocumentElement($xml); 
print OUT $doc->toString(1); 

schéma d'entrée:

<xs:schema xmlns="urn:testsample" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:testsample" elementFormDefault="qualified"> 
    <xs:element name="Document"> 
      <xs:complexType> 
        <xs:sequence> 
          <xs:element ref="address" minOccurs="1" maxOccurs="unbounded"/> 
        </xs:sequence> 
      </xs:complexType> 
    </xs:element> 
    <xs:element name="address"> 
      <xs:complexType> 
        <xs:sequence> 
          <xs:element name="Pname" type="Pname" minOccurs="0" maxOccurs="1"/> 
          <xs:element ref="street" minOccurs="0" maxOccurs="3"/> 
          <xs:element name="contact" type="contacttype"/> 
        </xs:sequence> 
      </xs:complexType> 
    </xs:element> 
    <xs:complexType name="contacttype"> 
      <xs:choice> 
        <xs:element ref="bday" minOccurs="0" maxOccurs="1"/> 
        <xs:element ref="email" minOccurs="0" maxOccurs="1"/> 
        <xs:element ref="postal" minOccurs="0" maxOccurs="2"/> 
      </xs:choice> 
    </xs:complexType> 
    <xs:simpleType name="Pname"> 
      <xs:restriction base="xs:string"> 
        <xs:enumeration value="AA"/> 
        <xs:enumeration value="BB"/> 
      </xs:restriction> 
    </xs:simpleType> 
    <xs:element name="street" type="xs:string"/> 
    <xs:element name="email" type="xs:string"/> 
    <xs:element name="postal" type="xs:string"/> 
    <xs:element name="bday" type="xs:date"/> 
</xs:schema> 

La sortie est correcte. Pour aller plus loin, dans l'exemple de schéma, il y a des éléments de choix, des énumérations et des éléments répétitifs. Je voudrais:

1. iterate all the possible values 
2. generate maximum repetitive elements, if unbounded then 99 
3. generate all choice values 
4. split them into multiple XML files such that every XML is valid against the original schema. 

Les fichiers XML de sortie montant est: i * j (i: la quantité de choix dans chaque nœud récursive, peut être i1 * i2 * i3 ... j: la quantité de énumérations dans chaque nœud récursivement, peut être j1 * j2 * j3 ...)

Dans ce cas, il génère 2 * 3 = 6 fichiers XML (s'il y a un nœud incorporé avec 2 valeurs d'énumération, alors il devient 2 * 2 * 3 = 12 fichiers XML), similaires à:

fichier XML 1:

<x0:Document xmlns:x0="urn:testsample"> 
<x0:address> 
    <x0:Pname>AA</x0:Pname> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:contact> 
     <x0:email>example</x0:email> 
    </x0:contact> 
</x0:address> 
</x0:Document> 

fichier XML 2:

<x0:Document xmlns:x0="urn:testsample"> 
<x0:address> 
    <x0:Pname>BB</x0:Pname> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:contact> 
     <x0:email>example</x0:email> 
    </x0:contact> 
</x0:address> 
</x0:Document> 

fichier XML 3:

<x0:Document xmlns:x0="urn:testsample"> 
<x0:address> 
    <x0:Pname>AA</x0:Pname> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:contact> 
     <x0:bday>2017-10-2</x0:bday> 
    </x0:contact> 
</x0:address> 
</x0:Document> 

fichier XML 4:

<x0:Document xmlns:x0="urn:testsample"> 
<x0:address> 
    <x0:Pname>BB</x0:Pname> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:contact> 
     <x0:bday>2017-10-2</x0:bday> 
    </x0:contact> 
</x0:address> 
</x0:Document> 

fichier XML 5:

<x0:Document xmlns:x0="urn:testsample"> 
<x0:address> 
    <x0:Pname>AA</x0:Pname> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:contact> 
     <x0:postal>example</x0:postal> 
     <x0:postal>example</x0:postal> 
    </x0:contact> 
</x0:address> 
</x0:Document> 

fichier XML 6:

<x0:Document xmlns:x0="urn:testsample"> 
<x0:address> 
    <x0:Pname>BB</x0:Pname> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:street>example</x0:street> 
    <x0:contact> 
     <x0:postal>example</x0:postal> 
     <x0:postal>example</x0:postal> 
    </x0:contact> 
</x0:address> 
</x0:Document> 

je tout d'abord bloqué pour obtenir la valeur correcte pour i et j, car ils seront variables utilisées dans les noms de fichiers XML générés, puis le possible Divisé. Toute aide est appréciée!

+0

Êtes-vous en train de construire un test unitaire de toutes les paires pour votre schéma? – simbabque

+0

Oui, c'est en quelque sorte l'idée – dellair

+0

Je lui ai donné une seconde cependant, peut-être modifier le module XML :: Compile, pour donner une valeur/étiquette spéciale à l'énumération et au choix, puis diviser le XML généré. Par exemple: AAENUMERATION1 BBENUMERATION2 2017-10-2CHOICE1 exampleCHOICE2 exampleCHOICE3 dellair

Répondre

6

(Je suis l'auteur de XML :: Compile) Cela ne peut jamais conduire à une solution générique, il est donc sans doute pas la peine ...

Presque tous les éléments ont des valeurs différentes que vous devez test, l'énumération semble être spéciale, mais ne l'est pas. Par exemple, un entier est aussi une énumération. Voulez-vous marcher toutes ses valeurs? Le nombre de combinaisons explose.

Lorsque vous souhaitez collecter plus d'informations à partir du schéma que ne le montre la fonction template(), essayez d'étendre XML :: Compile :: Translate :: Template. Il vous offre des détails à partir du xsd dans des structures HASH simples.

Succès

+2

Je lis juste le Traduisez, presque. Merci pour la réponse et l'excellent travail sur le module !!! – dellair

3

Vous ne semblez pas avoir une bonne compréhension de la taille des effectifs concernés.

Permettez-moi d'ajouter quelques limites:

  • Nous limitons bornés répétitions à quatre cas de test de min, min+1, max-1 et max répétitions.
  • Nous limitons les répétitions illimitées à trois cas de test de min, min+1 et min+100 répétitions.
  • Nous utilisons toujours la même valeur pour xs:string et xs:date.

Même avec ces limites, votre schéma trivialement simple, entraînerait 4   × combinaisons (ou 4   × combinaisons si nous réduisons le troisième cas de répétitions sans bornes de min+100 à min+10). Pour avoir une idée de l'échelle de ces nombres, considérez ceci: Il n'y a que 10 atomes dans l'univers observable.

Une solution générique n'est simplement pas possible.


Le nombre a été obtenu en utilisant le programme suivant:

use strict; 
use warnings qw(all); 
use feature qw(say); 

sub sum { my $acc = 0; $acc += $_ for @_; $acc } 
sub mul { my $acc = 1; $acc *= $_ for @_; $acc } 

sub choice { sum @_ } 
sub sequence { mul @_ } 

sub repeat { 
    my ($x, $min, $max) = @_; 
    my @exps; 
    if (defined($max)) { 
     @exps = ($min, $min+1, $max-1, $max); 
     my $diff = $max - $min; 
     die if $diff < 0; 
     splice @exps, $diff+1 if $diff < 3; 
    } else { 
     @exps = ($min, $min+1, $min+100); 
    } 

    return choice map { $x ** $_ } @exps; 
} 

# optional($x) is a shortcut for repeat($x, 0, 1) 
sub optional { 1 + $_[0] } 

sub Document { repeat(address(), 1) } 
sub address { sequence optional(Pname()), repeat(street(), 0, 3), contacttype() } 
sub contacttype { optional(contacttype_choice()) } 
sub contacttype_choice { choice bday(), email(), repeat(postal(), 1, 2) } 
sub Pname { 2 } 
sub street { 1 } 
sub bday { 1 } 
sub email { 1 } 
sub postal { 1 } 

say Document(); 

Le programme ci-dessus utilise la définition plus simple, mais équivalent suivant de contacttype:

<xs:complexType name="contacttype"> 
     <xs:choice minOccurs="0" maxOccurs="1"> 
       <xs:element ref="bday"/> 
       <xs:element ref="email"/> 
       <xs:element ref="postal" minOccurs="1" maxOccurs="2"/> 
     </xs:choice> 
</xs:complexType> 
+0

Merci @ikegami, tu as raison, j'avais modifié mon script pour faire une combinaison non-complète de ces itérations. c'est-à-dire: combinaison d'énumérations 1, d'énumérations 2, etc., ainsi que la combinaison de choix 1, choix 2. maxOccurs 99 par défaut (si non spécifié), maxLength 399 par défaut (si non spécifié), d'autres restrictions ont été définies pour répondre mon exigence spécifique - aucune garantie si cette logique couvre tous les cas généraux. – dellair

+0

Vous avez mentionné ces restrictions (sauf la longueur maximale qui est impossible à vérifier jusqu'à ce que vous ayez dîné le travail). J'ai utilisé ces restrictions et ajouté quelques restrictions en plus de celles-ci pour obtenir ces chiffres énormes. – ikegami