Validating with XML::LibXML::RelaxNG?
Rodent of Unusual Size <[email protected]>
| Newsgroups | gmane.comp.lang.perl.xml |
|---|---|
| Organization | CPAN |
| Message-ID | <[email protected]> |
I'm getting seemingly anomalous results when using XML::LibXML::RelaxNG to validate documents. Firstly, is an instance supposed to be reusable? Can it be used to validate multiple RNG documents in sequence? Or do I need to instantiate a new object for each document I want to validate? Empirical evidence suggests the former, but it doesn't appear to be clearly spelt out in the docco. Next: I'm using XML::LibXML::RelaxNG to verify a schema -- sort of working in both directions, as it were. I build a document incrementally and validate it at each stage to make sure that a) I'm not messing up the structure of the document as I build it, and b) that the RNG schema agrees with me about what's valid. Included in the testing are intentional errors to make sure the schema catches them, too. If I take this incremental document and export it to XML with its toString() method, create a new document from it with XML::LibXML->new(string => $foo), and pass the result to $rng->validate(), it *always* behaves as expected. If I pass it the XML::LibXML::Document object I've been frobbing, it sometimes says the invalid XML is, in fact, valid. I'm frobbing the document with addChild() and removeChild(), using element objects I created at the beginning with createElement(). In other words, the same nodes are getting moved around: inserted here, removed and re-inserted over there, etc. The document's toString() output shows the correct XML. Is what I'm doing with shuffling nodes not supported at some level? Are there artifacts of the shuffling that are getting left behind and confusing the RNG validator when it scans the DOM document? I've got a test case that illustrates the behaviour. I'm attaching the schema in RNC and RNG format, the Perl demonstrating the behaviour, and the output from the script. I basically build the document by hand and run it through the validator four times. For each run, the output contains the XML (from the document's toString() method), the results of eval'ing validation on the document-as-modified, and the results from validating a new document created from the XML. The last case shows that validation of the bad XML fails as expected, but does *not* fail on the document from which the XML was extracted. Am I misusing the document manipulation mechanisms? Or should this work and I've found a bug? Or what? Thanks! -- #ken P-)} Ken Coar, Sanagendamgagwedweinini http://Ken.Coar.Org/ Author, developer, opinionist http://Apache-Server.Com/ "Millennium hand and shrimp!" _______________________________________________ Perl-XML mailing list [email protected] To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
demo.rnc
(text/plain, 472 B)
namespace rng = "http://relaxng.org/ns/structure/1.0"
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes"
#
# The master container.
#
start =
element root
{
attribute.name,
element.onedown?
}
attribute.name = attribute name
{
text
}
element.onedown = element onedown
{
attribute.name?,
element.twodown*
}
element.twodown = element twodown
{
attribute.name
}
demo.rng
(text/xml, 761 B)
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
<!--
The master container.
-->
<start>
<element name="root">
<ref name="attribute.name"/>
<optional>
<ref name="element.onedown"/>
</optional>
</element>
</start>
<define name="attribute.name">
<attribute name="name"/>
</define>
<define name="element.onedown">
<element name="onedown">
<optional>
<ref name="attribute.name"/>
</optional>
<zeroOrMore>
<ref name="element.twodown"/>
</zeroOrMore>
</element>
</define>
<define name="element.twodown">
<element name="twodown">
<ref name="attribute.name"/>
</element>
</define>
</grammar>
demo.pl
(text/plain, 1.9 KB)
#! /usr/bin/perl -w
use strict;
use warnings;
use Test::More;
use Carp;
use Data::Dumper;
use File::Spec;
use XML::LibXML;
my $parser = XML::LibXML->new();
my $rng = XML::LibXML::RelaxNG->new(location => 'demo.rng');
my $seed_xml = <<'EOXML';
<?xml version="1.0" encoding="UTF-8"?>
<root/>
EOXML
my $doc = $parser->parse_string($seed_xml);
my $xpath = XML::LibXML::XPathContext->new($doc);
my ($rootElem) = $xpath->findnodes('//root', $doc);
my $bogusElem = $doc->createElement('bogus-element');
my $onedownElem = $doc->createElement('onedown');
my $twodownElem = $doc->createElement('twodown');
my $xml;
my @results;
my $result;
#
# Should fail; the root element needs a 'name' attribute.
#
$@ = undef;
$xml = $doc->toString(2);
eval('$rng->validate($doc);');
$result = $@;
eval('$rng->validate($parser->parse_string($xml));');
push(@results, { xml => "\n$xml", raw => "$@", DOM => "$result"});
#
# Should succeed; the root element is now complete.
#
$rootElem->setAttribute('name', 'rootElem');
$@ = undef;
$xml = $doc->toString(2);
eval('$rng->validate($doc);');
$result = $@;
eval('$rng->validate($parser->parse_string($xml));');
push(@results, { xml => "\n$xml", raw => "$@", DOM => "$result"});
#
# Should succeed; the root element now has a vali child.
#
$rootElem->addChild($onedownElem);
$@ = undef;
$xml = $doc->toString(2);
eval('$rng->validate($doc);');
$result = $@;
eval('$rng->validate($parser->parse_string($xml));');
push(@results, { xml => "\n$xml", raw => "$@", DOM => "$result"});
#
# Should fail; the root element can't have <twodown/> as a child.
#
$rootElem->addChild($twodownElem);
$@ = undef;
$xml = $doc->toString(2);
eval('$rng->validate($doc);');
$result = $@;
eval('$rng->validate($parser->parse_string($xml));');
push(@results, { xml => "\n$xml", raw => "$@", DOM => "$result"});
print Dumper(\@results);
#
# Local Variables:
# mode: cperl
# tab-width: 4
# indent-tabs-mode: nil
# End:
#
output.txt
(text/plain, 967 B)
$VAR1 = [
{
'xml' => '
<?xml version="1.0" encoding="UTF-8"?>
<root/>
',
'DOM' => 'unknown-9da80b0:0: Relax-NG validity error : Element root failed to validate attributes
',
'raw' => 'unknown-a0154f0:0: Relax-NG validity error : Element root failed to validate attributes
'
},
{
'xml' => '
<?xml version="1.0" encoding="UTF-8"?>
<root name="rootElem"/>
',
'DOM' => '',
'raw' => ''
},
{
'xml' => '
<?xml version="1.0" encoding="UTF-8"?>
<root name="rootElem">
<onedown/>
</root>
',
'DOM' => '',
'raw' => ''
},
{
'xml' => '
<?xml version="1.0" encoding="UTF-8"?>
<root name="rootElem">
<onedown/>
<twodown/>
</root>
',
'DOM' => '',
'raw' => 'unknown-a014ff8:0: Relax-NG validity error : Did not expect element twodown there
'
}
];