XMLReader fails to load relax-ng schema

I don’t know why php XMLReader library fails to load all my xml-schemas including some pretty basics.

Each time I end up with the following message: Warning: XMLReader::setRelaxNGSchemaSource() [xmlreader.setrelaxngschemasource]: Unable to set schema. This must be set prior to reading or schema contains errors. in /var/www/test.php on line 12

source code

Here is the source code that generated above error:

<?php
$rng_schema = <<<RNG
<?xml version="1.0"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<element name="node1"><text/></element>
</start>
</grammar>
RNG;
$xml_reader = new XMLReader();
$xml_reader->setRelaxNGSchemaSource($rng_schema);

workaround

My relax-ng schemas looks like working if using xmllint (part of libxml2-tools package) or sun-microsystem “msv” validator (https://msv.dev.java.net/).

Both of them return an error code if validation failed. We can use it to emulate a relax-ng validator calling them from php. Personnaly I prefer using xmllint since it bypasses java:

$output = shell_exec('xmllint --relaxng <path-to-relax-ng-schema.rng> <path-to-xml-file> > /dev/null 2>&1; echo $?');
if ('0' === trim($output)) {
  // when validation succeeds
} else {
  // when validation fails
}

sources

4 Comments: Trackback URL | Comments RSS

  1. Rob Richards Says:

    You need to set the data for the reader prior to calling this. xmllint works because you pass it both at same time so it can create a reader. I will provide a more descriptive error for this case.
  2. remy Says:

    Rob, thanks for your answer. Settting data prior to setting relax-ng schema indeeds remove the error message. But it looks like relax-ng validation fails. With the following piece of code, my xml input is not valid (<node1> is expected, not <node2>), but XMLReader still returns true!
    $rng_schema = <<<RNG
    <?xml version="1.0"?>
    <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
    	<start>
    		<element name="node1"><text/></element>
    	</start>
    </grammar>
    RNG;
    $xml_data = <<<XML
    <?xml version="1.0"?>
    <node2/>
    XML;
    $xml_reader = new XMLReader();
    $xml_reader->xml($xml_data);
    $xml_reader->setRelaxNGSchemaSource($rng_schema);
    $xml_reader->setParserProperty(XMLReader::VALIDATE, true);
    var_dump($xml_reader->isValid());
    #expected output: bool(false)
    #php output: bool(true)
    
    Output when calling xmllint:

    node1.xml:2: element node2: Relax-NG validity error : Expecting element node1, got node2. node1.xml fails to validate

  3. Rob Richards Says:

    Dont set the validate parameter. That is used to validate against a DTD. Just setting the RelaxNG schema is enough to set it for relaxng validation. The other thing is that the output is correct. You haven't moved through the document at all and the reader's current state is valid. Once you moved to the node2 element, isValid will return false (and issue a PHP warning, so you might want to use the libxml_use_internal_errors() function.
  4. remy Says:

    Thanks Rob for your explanations. I've added a similar comment on php online manual so that if someone else runs into such trouble it could be useful as well.

Post a Comment

Your email is never published nor shared. You're allow to say what you want...