[Xml-compile] minOccurs=0 and nillable="true" woes

Michael van der Westhuizen michael.vanderwesthuizen at voss-solutions.com
Fri Nov 13 09:52:48 GMT 2009


Hi All,

I have a rather large vendor schema I need to interact with that makes  
very heavy use of elements with both minOccurs=0 and  
nillable="true" (138 instances of this combination).

I'm finding that the behavior of XML::Compile::Schema is a bit non- 
intuitive in this case - the list archives suggest that this is a  
known weakness, but unfortunately the default behavior is to produce  
invalid XML documents (both syntactically and semantically), which is  
definitely a problem for us. The problems we're seeing are in the  
writer.

The first case, setting the data, works as expected.
The second case, setting the data to NIL, works as expected - we're  
happy with this.
The third case, setting the data to undef works as expected, but  
allows us to produce invalid XML documents (we can live with this,  
since the code is just doing what we said).
The last case, not setting the data, behaves as the third case does,  
which is a big problem for us.

I'd expect that when I do not send any data for a field which has  
minOccurs=0 that no XML is generated for that element, irrespective of  
the setting of nillable. Nillable, in this case, means something  
completely different to "not present" (in the vendor schema "not  
present" means leave as is, nil means set to nil - we need to do both).

I've appended a reduced schema and test cases that illustrate this  
behavior.

Is there any chance of this being resolved? I'd hate to have to go  
back to writing XML manually! I've poked around the Translate reader  
and writer code and I can't find anywhere that looks suitable for a fix.

Michael


--- mike.xsd ---
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     targetNamespace="http://www.visionoss.com/schema/UCMPROXY/1.0"
     xmlns:tns="http://www.visionoss.com/schema/UCMPROXY/1.0"
     elementFormDefault="qualified" version="1.0">

   <xsd:complexType name="XDevice">
     <xsd:sequence>
       <xsd:element name="name" type="xsd:string"/>
       <xsd:element name="devicePoolName" type="xsd:string"/>
       <xsd:element name="someSortOfId" type="xsd:positiveInteger"  
nillable="true" minOccurs="0"/>
     </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="addDevice">
     <xsd:complexType>
       <xsd:sequence>
         <xsd:element name="newDevice" type="tns:XDevice"  
nillable="false"/>
       </xsd:sequence>
     </xsd:complexType>
   </xsd:element>
</xsd:schema>
--- end mike.xsd ---

--- test case ---
use XML::Compile::Schema ();
use XML::LibXML;

my $schema = XML::Compile::Schema->new('mike.xsd');
my $xdevice_writer = $schema->compile(WRITER => "{http:// 
www.visionoss.com/schema/UCMPROXY/1.0}addDevice");

my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');

my $expected1 = '<x0:addDevice xmlns:x0="http://www.visionoss.com/schema/UCMPROXY/1.0 
" xmlns:xsi="http://www.w3.org/2001/XMLSchema- 
instance"><x0:newDevice><x0:name>abc</ 
x0:name><x0:devicePoolName>devicepool1</ 
x0:devicePoolName><x0:someSortOfId xsi:nil="true"/></x0:newDevice></ 
x0:addDevice>';
my $hash = {newDevice => {name => 'abc', devicePoolName =>  
'devicepool1', someSortOfId => 'NIL' }};
print sprintf("TEST 1: exists: %d, defined %d, value '%s'\n", exists  
$hash->{newDevice}->{someSortOfId}, defined $hash->{newDevice}-> 
{someSortOfId}, $hash->{newDevice}->{someSortOfId});
my $node = $xdevice_writer->($doc, $hash);
my $s = $node->toString(0);
if ($s eq $expected1) {
     print "optional, nillable, NIL OK\n";
} else {
     print "optional, nillable, NIL FAIL\n";
}

my $expected2 = '<x0:addDevice xmlns:x0="http://www.visionoss.com/schema/UCMPROXY/1.0 
" xmlns:xsi="http://www.w3.org/2001/XMLSchema- 
instance"><x0:newDevice><x0:name>abc</ 
x0:name><x0:devicePoolName>devicepool1</ 
x0:devicePoolName><x0:someSortOfId></x0:someSortOfId></x0:newDevice></ 
x0:addDevice>';
$hash = {newDevice => {name => 'abc', devicePoolName => 'devicepool1',  
someSortOfId => undef }};
print sprintf("TEST 2: exists: %d, defined %d, value undef\n", exists  
$hash->{newDevice}->{someSortOfId}, defined $hash->{newDevice}-> 
{someSortOfId});
$node = $xdevice_writer->($doc, $hash);
$s = $node->toString(0);
if ($s eq $expected2) {
     print "optional, nillable, undef OK (invalid anyway, but that's  
expected)\n";
} else {
     print "optional, nillable, undef FAIL\n";
}

my $expected3 = '<x0:addDevice xmlns:x0="http://www.visionoss.com/schema/UCMPROXY/1.0 
" xmlns:xsi="http://www.w3.org/2001/XMLSchema- 
instance"><x0:newDevice><x0:name>abc</ 
x0:name><x0:devicePoolName>devicepool1</x0:devicePoolName></ 
x0:newDevice></x0:addDevice>';
$hash = {newDevice => {name => 'abc', devicePoolName =>  
'devicepool1' }};
print sprintf("TEST 3: exists: %d, defined %d, value not present\n",  
exists $hash->{newDevice}->{someSortOfId}, defined $hash->{newDevice}-> 
{someSortOfId});
$node = $xdevice_writer->($doc, $hash);
$s = $node->toString(0);
if ($s eq $expected3) {
     print "optional, nillable, missing OK\n";
} else {
     print "optional, nillable, missing FAIL (this one kills us)\n";
}
--- end test case ---





More information about the Xml-compile mailing list