【问题标题】:XML::Compile to generate sample XML from schema with enumeration and choiceXML::Compile 通过枚举和选择从模式生成示例 XML
【发布时间】:2018-03-13 09:34:36
【问题描述】:

按照一些现有的教程,我在 perl 脚本下面创建了从 xsd 生成 XML。

脚本:

#!/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);

输入架构:

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

输出是正确的。更进一步,在示例模式中,有选择元素、枚举和重复元素。我想:

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. 

输出的XML文件数量为:i*j(i:递归每个节点的选择数量,可以是i1*i2*i3... j:递归每个节点的枚举数量,可以是j1* j2*j3...)

此时输出2*3=6个XML文件(如果有嵌入节点有2个枚举值,则变成2*2*3=12个XML文件),类似:

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>

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>

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>

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>

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>

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>

我首先坚持为 i 和 j 获取正确的值,因为它们将是生成的 XML 文件名中使用的变量,然后是可能的拆分。任何帮助表示赞赏!

【问题讨论】:

  • 您是否正在尝试为您的架构构建一个全对单元测试?
  • 是的,就是这样
  • 我给了它一秒钟,也许修改 XML::Compile 模块,给枚举和选择一些特殊的值/标签,然后拆分生成的 XML。例如:AAENUMERATION1BBENUMERATION22017-10-2CHOICE1exampleCHOICE2exampleCHOICE3

标签: xml perl xsd


【解决方案1】:

(我是 XML::Compile 的作者) 这永远不会导致通用解决方案,因此可能不值得付出努力......

几乎所有元素都有不同的值需要测试,枚举似乎很特殊,但并非如此。例如,整数也是枚举。你会走它的所有价值观吗?组合的数量爆炸式增长。

如果您想从模式中收集比 template() 函数显示的更多信息,请尝试扩展 XML::Compile::Translate::Template。它以简单的 HASH 结构为您提供来自 xsd 的详细信息。

成功

【讨论】:

  • 我只是在读翻译,差不多了。感谢您的回答和模块上的出色工作!!!
【解决方案2】:

您似乎没有掌握所涉及的数字的大小。

让我添加一些限制:

  • 我们将有界重复限制为 minmin+1max-1max 重复这四个测试用例。
  • 我们将无限重复限制为minmin+1min+100 重复三个测试用例。
  • 我们始终为xs:stringxs:date 使用相同的值。

即使有这些限制,您的简单架构也会产生 4 × 10179 组合(如果我们减少无限制重复的第三种情况,则为 4 × 1019 组合从min+100min+10)。

要了解这些数字的大小,请考虑以下情况:可观测宇宙中只有 1080 个原子。

一个通用的解决方案是不可能的。


号码是使用以下程序获得的:

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>

【讨论】:

  • 谢谢@ikegami,你是对的,我已经修改了我的脚本来做这些迭代的非完整组合。即:枚举1、枚举2等的组合,以及选项1、选项2的组合。默认maxOccurs 99(如果未指定),默认maxLength 399(如果未指定),已设置一些其他限制以满足我的具体要求 - 不能保证此逻辑是否涵盖所有一般情况。
  • 你确实提到了这些限制(除了最大长度,直到你吃完工作后才能检查)。我使用了这些限制,并在这些限制之上添加了一些我自己的限制来获得这些巨大的数字。
猜你喜欢
  • 2011-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 2022-07-01
相关资源
最近更新 更多