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]