Curse me, and my cut and copy errors! The non-working example should should have no "tns" namespaces, only "my-tns"

It should read:

<my-tns:Body xmlns:my-tns="http://www.example.com/qname";
             xmlns:xml="http://www.w3.org/XML/1998/namespace";>
 <my-tns:Fault>
   <my-tns:Code>
    <my-tns:Value>my-tns:Sender</my-tns:Value>
   </my-tns:Code>
 </my-tns:Fault>
</my-tns:Body>

-Alex



Alberto Massari wrote:

Hi Alex,
I just gave a cursory look to your letter, but it looks to me that you are using in your XML a prefix (tns) that is not declared. Have you tried changing the XML to be like this?

<my-tns:Body xmlns:my-tns="http://www.example.com/qname";
             xmlns:tns="http://www.example.com/qname";
             xmlns:xml="http://www.w3.org/XML/1998/namespace";>

Alberto

At 10.43 13/06/2005 -0700, Alex Dickinson wrote:

Hello,

I am using Xerces-c to validate SOAP XML, and I have encountered a problem that I would like some input on.

SOAP defines is fault codes as enumerations with a QName base. If an XML document is validated against the SOAP XMLSchema, it will validate only if the enumeration's QName's prefix is exactly the same as the namespace prefix defined in the XSD.

For example, the schema is defined as:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";
          xmlns:tns="http://www.example.com/qname";
          xmlns:xml="http://www.w3.org/XML/1998/namespace";
          targetNamespace="http://www.example.com/qname";
        elementFormDefault="qualified" > ...
(the full schema is included below)

Then the XML document will validate (using same namespace prefix):

<tns:Body xmlns:tns="http://www.example.com/qname";
             xmlns:xml="http://www.w3.org/XML/1998/namespace";>
 <tns:Fault>
   <tns:Code>
      <tns:Value>tns:Sender</tns:Value>
   </tns:Code>
 </tns:Fault>
</tns:Body>

But the following will not (using a different namespace prefix):

<tns:Body xmlns:my-tns="http://www.example.com/qname";
             xmlns:xml="http://www.w3.org/XML/1998/namespace";>
 <my-tns:Fault>
   <my-tns:Code>
      <my-tns:Value>tns:Sender</my-tns:Value>
   </my-tns:Code>
 </my-tns:Fault>
</my-tns:Body>


I have tracked the root of this problem down to trunk/src/xercesc/validators/datatype/QNameDatatypeValidator.cpp line 185:

       for ( ; i < enumLength; i++)
       {
if (XMLString::equals(normContent, getEnumeration()->elementAt(i)))
               break;
       }

       if (i == enumLength)
ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, content, manager);

The comparison XMLString::equals is comparing the QName string with the URI prefix (i.e. tns:Sender) instead of the the URI itself (i.e. {http://www.example.com/qname}:Sender). So if the XML uses a different namespace prefix than that of the schema definition, it will fail.

I have included a .xsd and a sample parser that demonstrates the error.

Cheers,
Alex Dickinson (long time listener, first time caller)

-------------------------------------------------
Full Schema:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";
          xmlns:tns="http://www.example.com/qname";
          xmlns:xml="http://www.w3.org/XML/1998/namespace";
          targetNamespace="http://www.example.com/qname";
        elementFormDefault="qualified" >

 <xs:import namespace="http://www.w3.org/XML/1998/namespace";
        schemaLocation="http://www.w3.org/2001/xml.xsd"; />

 <xs:element name="Body" type="tns:Body" />
 <xs:complexType name="Body" >
   <xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
   </xs:sequence>
   <xs:anyAttribute namespace="##other" processContents="lax" />
 </xs:complexType>

 <xs:element name="Fault" type="tns:Fault" />
 <xs:complexType name="Fault" final="extension" >
   <xs:sequence>
     <xs:element name="Code" type="tns:faultcode" />
   </xs:sequence>
 </xs:complexType>

 <xs:complexType name="faultcode">
   <xs:sequence>
     <xs:element name="Value"
                 type="tns:faultcodeEnum"/>
   </xs:sequence>
 </xs:complexType>

 <xs:simpleType name="faultcodeEnum">
   <xs:restriction base="xs:QName">
     <xs:enumeration value="tns:DataEncodingUnknown"/>
     <xs:enumeration value="tns:MustUnderstand"/>
     <xs:enumeration value="tns:Receiver"/>
     <xs:enumeration value="tns:Sender"/>
     <xs:enumeration value="tns:VersionMismatch"/>
   </xs:restriction>
 </xs:simpleType>

</xs:schema>


-------------------------------------------------
Parsing code:


#include <xercesc/dom/DOMBuilder.hpp>
#include <xercesc/dom/DOMErrorHandler.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMImplementationRegistry.hpp>
#include <xercesc/dom/DOMLocator.hpp>
#include <xercesc/dom/DOMNode.hpp>
#include <xercesc/validators/common/Grammar.hpp>

#include <iostream>

XERCES_CPP_NAMESPACE_USE


/**
* Defined a DOM Error handler that will report errors to stdout
*/
class XMLErrorHandler : public DOMErrorHandler
{
 public:
   XMLErrorHandler() : DOMErrorHandler() { }
   ~XMLErrorHandler() { }

   virtual bool handleError(const DOMError &domError)
   {
     bool rc;

std::cout << "---------------------------------------" << std::endl;
     switch( domError.getSeverity() )
     {
       case DOMError::DOM_SEVERITY_WARNING :
         std::cout << "Warning:" << std::endl;
         rc = true;
         break;

       case DOMError::DOM_SEVERITY_ERROR:
         std::cout << "Error:" << std::endl;
         rc = true;
         break;

       case DOMError::DOM_SEVERITY_FATAL_ERROR:
         std::cout << "Fatal Error:" << std::endl;
         rc = false;
         break;

       default:
         std::cout << "Unknown Error:" << std::endl;
         rc = false;
     }

     DOMLocator *pLocation = domError.getLocation();

std::cout << "\tLine: " << pLocation->getLineNumber() << std::endl; std::cout << "\tColumn: " << pLocation->getColumnNumber() << std::endl;
     std::cout << "\tOffset:  " << pLocation->getOffset() << std::endl;

     char buffer[1024];
     DOMNode *pDomNode = pLocation->getErrorNode();
     XMLString::transcode(pDomNode->getNodeName(), buffer, 1023);
     std::cout << "Node: " << buffer << std::endl;

     XMLString::transcode(pLocation->getURI(), buffer, 1023);
     std::cout << "URI: " << buffer << std::endl;

     XMLString::transcode(domError.getMessage(), buffer, 1023);
     std::cout << "Msg: " << buffer << std::endl;
     std::cout << std::endl;
     return rc;
   }
};


int main(int argc, char* argv[])
{
 if (argc != 3)
 {
   std::cerr << "Usage: " << argv[0] << " <XML> <XSD>" << std::endl;
   return 1;
 }

 char* xmlFile = argv[1];
 char* xsdFile = argv[2];

 XMLPlatformUtils::Initialize();

 XMLErrorHandler eh;

 static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull };
DOMImplementation *pDomImpl = DOMImplementationRegistry::getDOMImplementation( gLS );

DOMBuilder *parser = ((DOMImplementationLS*)pDomImpl)->createDOMBuilder(
     DOMImplementationLS::MODE_SYNCHRONOUS, 0 );

 parser->setErrorHandler( &eh );
 parser->setFeature( XMLUni::fgDOMNamespaces, true );
 parser->setFeature( XMLUni::fgXercesSchema, true );
 parser->setFeature( XMLUni::fgXercesSchemaFullChecking, true );
 parser->setFeature( XMLUni::fgDOMValidation, true );
 parser->setFeature( XMLUni::fgXercesCacheGrammarFromParse, true);

 parser->loadGrammar( xsdFile, Grammar::SchemaGrammarType, true);
 parser->parseURI( xmlFile );

 XMLPlatformUtils::Terminate();
 return 0;
}




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to