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
'
          }
        ];
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.