valk
valk

Reputation: 9894

XML validation with XSD

I have this XML of products which I'm trying to validate.

(i keep it in xml.xml file)

<?xml version="1.0" encoding="UTF-8"?>
<catalog label="global">
    <catalog label="animals" link="/animals.php">
    <subject>Subject1</subject>
     </catalog>
    <catalog label="animals" link="/animals.php">
    <subject>Subject2</subject>
     </catalog>
</catalog>

Generated XSD with this tool: (i put in file xml.xsd)

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="catalog" type="catalogType" />
  <xsd:complexType name="catalogType">
    <xsd:sequence>
      <xsd:element maxOccurs="unbounded" name="catalog" type="catalogType" />
    </xsd:sequence>
    <xsd:attribute name="label" type="xsd:string" />
  </xsd:complexType>
  <xsd:complexType name="catalogType">
    <xsd:sequence>
      <xsd:element name="subject" type="xsd:string" />
    </xsd:sequence>
    <xsd:attribute name="label" type="xsd:string" />
    <xsd:attribute name="link" type="xsd:string" />
  </xsd:complexType>
</xsd:schema>

And the PHP code which I use to test them (in php.php file):

<?php 

function libxml_display_error($error) 
{ 
  $return = "<br/>\n"; 
  switch ($error->level) { 
  case LIBXML_ERR_WARNING: 
  $return .= "<b>Warning $error->code</b>: "; 
  break; 
  case LIBXML_ERR_ERROR: 
  $return .= "<b>Error $error->code</b>: "; 
  break; 
  case LIBXML_ERR_FATAL: 
  $return .= "<b>Fatal Error $error->code</b>: "; 
  break; 
  } 
  $return .= trim($error->message); 
  if ($error->file) { 
  $return .= " in <b>$error->file</b>"; 
  } 
  $return .= " on line <b>$error->line</b>\n"; 

  return $return; 
} 

    function checkXMLStructure($xml_object)
    {
        $xmlElement = $xml_object->catalog;
        $dom_sxe = dom_import_simplexml($xmlElement);

        $dom = new DOMDocument('1.0');
        $dom_sxe = $dom->importNode($dom_sxe, true);
        $dom_sxe = $dom->appendChild($dom_sxe);

        if ( !$dom->schemaValidate( dirname(__FILE__) . '/xml.xsd') ) {
            echo "BAD XML\n";
        return;
        }

        echo "*GOOD* XML!\n";
    }

// Enable user error handling 
libxml_use_internal_errors(true);

$xml_object = simplexml_load_file('xml.xml');
checkXMLStructure($xml_object);

// Display Errors
$errors = libxml_get_errors(); 
foreach ($errors as $error) { 
print libxml_display_error($error); 
} 
libxml_clear_errors();

The output:

PHP Warning:  DOMDocument::schemaValidate(): Element '{http://www.w3.org/2001/XMLSchema}complexType': A global complex type definition 'catalogType' does already exist. in /path/php.php on line 13
PHP Stack trace:
PHP   1. {main}() /path/php.php:0
PHP   2. checkXMLStructure() /path/php.php:23
PHP   3. DOMDocument->schemaValidate() /path/php.php:13
PHP Warning:  DOMDocument::schemaValidate(): Invalid Schema in /path/php.php on line 13
PHP Stack trace:
PHP   1. {main}() /path/php.php:0
PHP   2. checkXMLStructure() /path/php.php:23
PHP   3. DOMDocument->schemaValidate() /path/php.php:13
BAD XML

I need to rewrite the schema such that it will notice the *many elements inside the main element (please note the same name usage).

Upvotes: 1

Views: 6809

Answers (1)

Petru Gardea
Petru Gardea

Reputation: 21658

I've used QTAssistant to generate the schema below (which validates the XML you have provided):

<?xml version="1.0" encoding="utf-8"?>
<!--W3C Schema generated by QTAssistant/W3C Schema Refactoring Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="catalog">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element maxOccurs="unbounded" name="catalog">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="subject" type="xsd:string" />
            </xsd:sequence>
            <xsd:attribute name="label" type="xsd:string" use="required" />
            <xsd:attribute name="link" type="xsd:string" use="required" />
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
      <xsd:attribute name="label" type="xsd:string" use="required" />
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

You could start from the above and tweak it as you go along.

Validation results:

Validation results

If you wish to manually fix the XSD your tool created, then make sure that you rename only the first two occurrences of the catalogType to something else (e.g. catalogType1).

Upvotes: 1

Related Questions