alexbuisson
alexbuisson

Reputation: 8469

Xerces XML validation with XSD

I try to validate XML file using a given XSD grammar file. But for now it always return error saying no declaration found for element ... and that for each element or attribute I have in my XML file.

To create the XSD i used that Free online XSD generator and if I check my xml within that XSD using the (Validator)[http://www.freeformatter.com/xml-validator-xsd.html] on the same site, everything looks fine.

So why Xerces fails ?

I use the following code to validate:

      XercesDOMParser domParser;
      if (domParser.loadGrammar(schemaFilePath.c_str(), Grammar::SchemaGrammarType) == NULL)
      {
        throw Except("couldn't load schema");
      }

      ParserErrorHandler parserErrorHandler;

      domParser.setErrorHandler(&parserErrorHandler);
      domParser.setValidationScheme(XercesDOMParser::Val_Always);
      domParser.setDoNamespaces(true);
      domParser.setDoSchema(true);
      domParser.setValidationSchemaFullChecking(true);

      domParser.parse(xmlFilePath.c_str());
      if(domParser.getErrorCount() != 0)
      {     
        throw Except("Invalid XML vs. XSD: " + parserErrorHandler.getErrors()); //merge a error coming from my interceptor ....
      }

My XML test file is:

<?xml version="1.0" encoding="UTF-8" ?>
<schemes signature="9fadde05">
    <!-- NOTE: Do not modify this file. 
     Any modifications will invalidate the signature and result in an invalid file! 
     This is an example scheme, param_set etc... can be rename / market or / product
    -->
    <scheme>
        <name>test1</name>
        <other>test2</other>
    </scheme>
    <param_set>
        <input>
            <height min="1060" max="1100" />
            <width min="1900" max="1940" />
        </input>
    </param_set>
</schemes>

And the XSD I use is:

<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="schemes">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="scheme">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:string" name="name"/>
              <xs:element type="xs:string" name="other"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="param_set">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="input">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="height">
                      <xs:complexType>
                        <xs:simpleContent>
                          <xs:extension base="xs:string">
                            <xs:attribute type="xs:short" name="min"/>
                            <xs:attribute type="xs:short" name="max"/>
                          </xs:extension>
                        </xs:simpleContent>
                      </xs:complexType>
                    </xs:element>
                    <xs:element name="width">
                      <xs:complexType>
                        <xs:simpleContent>
                          <xs:extension base="xs:string">
                            <xs:attribute type="xs:short" name="min"/>
                            <xs:attribute type="xs:short" name="max"/>
                          </xs:extension>
                        </xs:simpleContent>
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute type="xs:string" name="signature"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

Upvotes: 3

Views: 17926

Answers (2)

Ondřej Navr&#225;til
Ondřej Navr&#225;til

Reputation: 601

Just leaving some info here for others who may experience some troubles with xercesc.

The solution provided by the question author is useful, yet may not apply to your case. First, if you use setExternalSchemaLocation, you do not need to loadGrammar.

Second, if your schema handles namespaces, try out setExternalSchemaLocation as well.

My code:

xmlParser = std::make_unique<xercesc::XercesDOMParser>();
std::string xsdPath = "http://your.namespace.com path/to/schema.xsd";

xmlParser->setValidationScheme(xercesc::XercesDOMParser::Val_Always);
xmlParser->setDoNamespaces(true);
xmlParser->setDoSchema(true);
xmlParser->setValidationSchemaFullChecking(true);

//Finally...
xmlParser->setExternalSchemaLocation(xsdPath.c_str());

Note that there is no call to loadGrammar. Also, note that xercesc will not attempt to parse the schema until you call

xmlParser->parse(...);

Upvotes: 3

alexbuisson
alexbuisson

Reputation: 8469

I solve that issue the following code, and I think the setExternalNoNamespaceSchemaLocation is the trick. Note that I had also to rebuild an absolute path for the XSD.

    XMLPlatformUtils::Initialize();
    {
      XercesDOMParser domParser;
      bfs::path pXSD = absolute(schemaFilePath);      
      if (domParser.loadGrammar(pXSD.string().c_str(), Grammar::SchemaGrammarType) == NULL)
      {
        throw Except("couldn't load schema");
      }

      ParserErrorHandler parserErrorHandler;

      domParser.setErrorHandler(&parserErrorHandler);
      domParser.setValidationScheme(XercesDOMParser::Val_Always);
      domParser.setDoNamespaces(true);
      domParser.setDoSchema(true);
      domParser.setValidationSchemaFullChecking(true);

      domParser.setExternalNoNamespaceSchemaLocation(pXSD.string().c_str());

      domParser.parse(xmlFilePath.c_str());
      if(domParser.getErrorCount() != 0)
      {     
        throw Except("Invalid XML vs. XSD: " + parserErrorHandler.getErrors()); //merge a error coming from my interceptor ....
      }
    }
    XMLPlatformUtils::Terminate();

Upvotes: 8

Related Questions