XML :: Compilation to create an XML sample from an enumeration and selection schema

Following some existing tutorials, I created below a perl script to generate XML from xsd.

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);

Input Scheme:

<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>

The output is correct. To take it further, the example schema has selection elements, enumerations, and repeating elements. I would like to:

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. 

The sum of the output XML files: i * j (i: the number of options in each node is recursive, maybe i1 * i2 * i3 ... j: the number of transfers in each node is recursive, maybe j1 * j2 * j3 ...)

In this case, it outputs 2 * 3 = 6 XML files (if there is a built-in node with two enumeration values, then it becomes 2 * 2 * 3 = 12 XML files), similarly:

XML file 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>

XML file 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>

XML 3 File:

<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>

XML file 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>

XML 5 file:

<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>

XML 6 file:

<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>

, j, , XML , . !

+4
2

( XML:: Compile) , , , ...

, , , . , . ? .

, template(), XML:: Compile:: Translate:: Template. xsd HASH.

Success

+6

, .

:

  • min, min+1, max-1 max.
  • min, min+1 min+100.
  • xs:string xs:date.

4 10 <sup> 179 ( 4   10 19), min+100 min+10).

, : 10 80.

.


:

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();

- 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>
+3

Source: https://habr.com/ru/post/1686745/


All Articles