Fixed a problem when dealing with "xsi:schemaLocation"

This commit is contained in:
Zane U. Ji 2014-06-02 20:09:16 +08:00
parent c61ceec6d0
commit 3993927d66
2 changed files with 99 additions and 90 deletions

View File

@ -18,6 +18,7 @@
*/ */
#include <wx/wx.h> #include <wx/wx.h>
#include <wx/tokenzr.h>
#include <stdexcept> #include <stdexcept>
#include "xmlpromptgenerator.h" #include "xmlpromptgenerator.h"
#include "xmlencodinghandler.h" #include "xmlencodinghandler.h"
@ -285,21 +286,14 @@ void XMLCALL XmlPromptGenerator::attlistdeclhandler (
XML_StopParser ( d->p, false ); XML_StopParser ( d->p, false );
} }
int XMLCALL XmlPromptGenerator::externalentityrefhandler ( int XmlPromptGenerator::parseGrammar
XML_Parser p, ( PromptGeneratorData *d
const XML_Char *context, , const wxString &publicId
const XML_Char *base, , const wxString &systemId
const XML_Char *systemId, , const wxString &baseFileName
const XML_Char *publicId ) , Grammar::GrammarType type
)
{ {
// arg is set to user data in c'tor
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) p;
PromptGeneratorData *d = pThis->d.get();
// Either EXPAT or Xerces-C++ is capable of parsing DTDs. The advantage
// of Xerces-C++ is that it can access DTDs that are on the internet.
#if !PREFER_EXPAT_TO_XERCES_C
XercesDOMParser parser; XercesDOMParser parser;
parser.setDoNamespaces ( true ); parser.setDoNamespaces ( true );
parser.setDoSchema ( true ); parser.setDoSchema ( true );
@ -310,23 +304,20 @@ int XMLCALL XmlPromptGenerator::externalentityrefhandler (
parser.setErrorHandler ( &handler ); parser.setErrorHandler ( &handler );
parser.setEntityResolver ( &catalogResolver ); parser.setEntityResolver ( &catalogResolver );
wxString widePublicId = wxString::FromUTF8 ( publicId );
wxString wideSystemId = wxString::FromUTF8 ( systemId );
Grammar *rootGrammar; Grammar *rootGrammar;
try { try {
std::auto_ptr<InputSource> source ( WrapXerces::resolveEntity std::auto_ptr<InputSource> source ( WrapXerces::resolveEntity
( widePublicId , wideSystemId , d->basePath ) ); ( publicId , systemId , baseFileName ) );
if ( !source.get() ) if ( !source.get() )
{ {
wxLogError ( _T("Cann't open '%s'"), wideSystemId.c_str() ); wxLogError ( _T("Cann't open '%s'"), systemId.c_str() );
return XML_STATUS_ERROR; return XML_STATUS_ERROR;
} }
if ( pThis->TestDestroy() ) if ( TestDestroy() )
return XML_STATUS_ERROR; return XML_STATUS_ERROR;
rootGrammar = parser.loadGrammar ( *source, Grammar::DTDGrammarType ); rootGrammar = parser.loadGrammar ( *source, type );
if ( !rootGrammar ) if ( !rootGrammar )
return XML_STATUS_ERROR; return XML_STATUS_ERROR;
} }
@ -349,30 +340,81 @@ int XMLCALL XmlPromptGenerator::externalentityrefhandler (
} }
catch (...) catch (...)
{ {
wxLogError ( _T ( "Failed to load: %s %s"), widePublicId.c_str() wxLogError ( _T ( "Failed to load: %s %s"), publicId.c_str()
, wideSystemId.c_str() ); , systemId.c_str() );
return XML_STATUS_ERROR; return XML_STATUS_ERROR;
} }
DTDGrammar* grammar = ( DTDGrammar* ) rootGrammar; wxASSERT ( rootGrammar->getGrammarType() == type );
NameIdPoolEnumerator<DTDElementDecl> elemEnum = grammar->getElemEnumerator();
SubstitutionMap substitutions; if ( type == Grammar::DTDGrammarType )
while ( elemEnum.hasMoreElements() && !pThis->TestDestroy() )
{ {
const DTDElementDecl& curElem = elemEnum.nextElement(); DTDGrammar* grammar = ( DTDGrammar* ) rootGrammar;
pThis->buildElementPrompt ( d, &curElem, substitutions ); NameIdPoolEnumerator<DTDElementDecl> elemEnum
= grammar->getElemEnumerator();
SubstitutionMap substitutions;
while ( elemEnum.hasMoreElements() && !TestDestroy() )
{
const DTDElementDecl& curElem = elemEnum.nextElement();
buildElementPrompt ( d, &curElem, substitutions );
}
NameIdPoolEnumerator<DTDEntityDecl>
entityEnum = grammar->getEntityEnumerator();
while ( entityEnum.hasMoreElements() && !TestDestroy() )
{
const DTDEntityDecl &entity = entityEnum.nextElement();
d->entitySet.insert ( WrapXerces::toString ( entity.getName() ) );
}
}
else
{
wxASSERT ( type == Grammar::SchemaGrammarType );
SchemaGrammar* grammar = ( SchemaGrammar* ) rootGrammar;
RefHash3KeysIdPoolEnumerator<SchemaElementDecl> elemEnum = grammar->getElemEnumerator();
if ( !elemEnum.hasMoreElements() )
{
return XML_STATUS_ERROR;
}
SubstitutionMap substitutions;
buildSubstitutionMap ( substitutions, *grammar );
while ( elemEnum.hasMoreElements() && !TestDestroy() )
{
const SchemaElementDecl& curElem = elemEnum.nextElement();
buildElementPrompt ( d, &curElem, substitutions );
}
} }
NameIdPoolEnumerator<DTDEntityDecl> return TestDestroy() ? XML_STATUS_ERROR : XML_STATUS_OK;
entityEnum = grammar->getEntityEnumerator(); }
while ( entityEnum.hasMoreElements() && !pThis->TestDestroy() )
{
const DTDEntityDecl &entity = entityEnum.nextElement();
d->entitySet.insert ( WrapXerces::toString ( entity.getName() ) );
}
return pThis->TestDestroy() ? XML_STATUS_ERROR : XML_STATUS_OK; int XMLCALL XmlPromptGenerator::externalentityrefhandler (
XML_Parser p,
const XML_Char *context,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId )
{
// arg is set to user data in c'tor
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) p;
PromptGeneratorData *d = pThis->d.get();
// Either EXPAT or Xerces-C++ is capable of parsing DTDs. The advantage
// of Xerces-C++ is that it can access DTDs that are on the internet.
#if !PREFER_EXPAT_TO_XERCES_C
return pThis->parseGrammar
( d
, wxString::FromUTF8 ( publicId )
, wxString::FromUTF8 ( systemId )
, d->basePath
, Grammar::DTDGrammarType
);
#else // !PREFER_EXPAT_TO_XERCES_C #else // !PREFER_EXPAT_TO_XERCES_C
@ -476,75 +518,36 @@ void XmlPromptGenerator::handleSchema (
{ {
if ( !d->isRootElement ) if ( !d->isRootElement )
return; return;
wxString publicId, systemId;
// first check for XML Schema association // first check for XML Schema association
const char **schemaAttr = ( const char ** ) attr; // now redundant; could use attr const char **schemaAttr = ( const char ** ) attr; // now redundant; could use attr
wxString path;
for ( ; *schemaAttr; schemaAttr += 2 ) for ( ; *schemaAttr; schemaAttr += 2 )
{ {
// no namespace // no namespace
if ( !strcmp ( *schemaAttr, "xsi:noNamespaceSchemaLocation" ) ) if ( !strcmp ( *schemaAttr, "xsi:noNamespaceSchemaLocation" ) )
{ {
path = wxString ( schemaAttr[1], wxConvUTF8 ); systemId = wxString ( schemaAttr[1], wxConvUTF8 );
break; break;
} }
// with namespace -- check if this works // with namespace -- check if this works
else if ( !strcmp ( *schemaAttr, "xsi:schemaLocation" ) ) else if ( !strcmp ( *schemaAttr, "xsi:schemaLocation" ) )
{ {
const char *searchIterator = * ( schemaAttr + 1 ); wxStringTokenizer tokens ( wxString ( schemaAttr[1], wxConvUTF8 ) );
while ( *searchIterator && *searchIterator != ' ' && *searchIterator != '\t' && *searchIterator != '\n' ) size_t count = tokens.CountTokens();
searchIterator++; if ( count < 2 )
if ( *searchIterator ) return;
{ // TODO: Support multiple schemas
path = wxString ( searchIterator + 1, wxConvUTF8 ); publicId = tokens.GetNextToken();
break; systemId = tokens.GetNextToken();
}
} }
} }
if ( path.empty() ) int ret = parseGrammar ( d, publicId, systemId, d->basePath
{ , Grammar::SchemaGrammarType );
if ( ret != XML_STATUS_OK )
return; return;
}
wxString schemaPath = PathResolver::run ( path, ( d->auxPath.empty() ) ? d->basePath : d->auxPath);
std::auto_ptr<XercesDOMParser> parser ( new XercesDOMParser() );
parser->setDoNamespaces ( true );
parser->setDoSchema ( true );
parser->setValidationSchemaFullChecking ( true );
if ( TestDestroy() )
{
XML_StopParser ( d->p, false );
return;
}
Grammar *rootGrammar = parser->loadGrammar
( ( const XMLCh * ) WrapXerces::toString ( schemaPath ).GetData()
, Grammar::SchemaGrammarType
);
if ( !rootGrammar )
{
return;
}
SchemaGrammar* grammar = ( SchemaGrammar* ) rootGrammar;
RefHash3KeysIdPoolEnumerator<SchemaElementDecl> elemEnum = grammar->getElemEnumerator();
if ( !elemEnum.hasMoreElements() )
{
return;
}
SubstitutionMap substitutions;
buildSubstitutionMap ( substitutions, *grammar );
while ( elemEnum.hasMoreElements() && !TestDestroy() )
{
const SchemaElementDecl& curElem = elemEnum.nextElement();
buildElementPrompt ( d, &curElem, substitutions );
}
d->grammarFound = true; d->grammarFound = true;
XML_StopParser ( d->p, false ); XML_StopParser ( d->p, false );

View File

@ -131,6 +131,12 @@ class XmlPromptGenerator : public WrapExpat, public wxThread
const XML_Char *att_type, const XML_Char *att_type,
const XML_Char *dflt, const XML_Char *dflt,
int isrequired ); int isrequired );
int parseGrammar (
PromptGeneratorData *d,
const wxString &publicId,
const wxString &systemId,
const wxString &baseFileName,
xercesc::Grammar::GrammarType type );
static int XMLCALL externalentityrefhandler ( static int XMLCALL externalentityrefhandler (
XML_Parser p, XML_Parser p,
const XML_Char *context, const XML_Char *context,