Bug #161 Validation of TEI Lite DTD fails
Don't treat validation warning as error Prefer memory to temporary file
This commit is contained in:
parent
80229a3686
commit
4f97286f5e
|
@ -1,4 +1,5 @@
|
||||||
#include "wx/wx.h"
|
#include <wx/wx.h>
|
||||||
|
#include <wx/textbuf.h>
|
||||||
#include "xmlctrl.h"
|
#include "xmlctrl.h"
|
||||||
#include "validationthread.h"
|
#include "validationthread.h"
|
||||||
#include "wrapxerces.h"
|
#include "wrapxerces.h"
|
||||||
|
@ -42,7 +43,11 @@ void *ValidationThread::Entry()
|
||||||
myBuffer.c_str(),
|
myBuffer.c_str(),
|
||||||
myBuffer.size(),
|
myBuffer.size(),
|
||||||
mySystem,
|
mySystem,
|
||||||
this );
|
this,
|
||||||
|
// Don't be too harsh to new created documents, which may haven't
|
||||||
|
// associated any schema yet
|
||||||
|
/*forceCheckGrammar*/false,
|
||||||
|
wxTextBuffer::GetEOL() );
|
||||||
|
|
||||||
myBuffer.clear();
|
myBuffer.clear();
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
|
|
||||||
#include "wrapxerces.h"
|
#include "wrapxerces.h"
|
||||||
|
|
||||||
|
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||||
#include <xercesc/sax2/XMLReaderFactory.hpp>
|
#include <xercesc/sax2/XMLReaderFactory.hpp>
|
||||||
#include <xercesc/sax2/SAX2XMLReader.hpp>
|
#include <xercesc/sax2/SAX2XMLReader.hpp>
|
||||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||||
#include <xercesc/util/XMLUni.hpp>
|
#include <xercesc/util/XMLUni.hpp>
|
||||||
#include <xercesc/framework/MemBufInputSource.hpp>
|
#include <xercesc/framework/MemBufInputSource.hpp>
|
||||||
|
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -51,7 +53,6 @@ WrapXerces::WrapXerces()
|
||||||
{
|
{
|
||||||
WrapXerces::Init();
|
WrapXerces::Init();
|
||||||
|
|
||||||
errorPosition = std::make_pair ( 1, 1 );
|
|
||||||
catalogResolver = new XercesCatalogResolver();
|
catalogResolver = new XercesCatalogResolver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,135 +63,99 @@ WrapXerces::~WrapXerces()
|
||||||
|
|
||||||
bool WrapXerces::validate ( const wxString& fileName )
|
bool WrapXerces::validate ( const wxString& fileName )
|
||||||
{
|
{
|
||||||
SAX2XMLReader *parser = XMLReaderFactory::createXMLReader();
|
return validateMemory ( NULL, 0, fileName );
|
||||||
|
|
||||||
parser->setFeature ( XMLUni::fgSAX2CoreNameSpaces, true );
|
|
||||||
parser->setFeature ( XMLUni::fgSAX2CoreValidation, true );
|
|
||||||
parser->setFeature ( XMLUni::fgXercesDynamic, false );
|
|
||||||
parser->setFeature ( XMLUni::fgXercesSchema, true );
|
|
||||||
parser->setFeature ( XMLUni::fgXercesSchemaFullChecking, true );
|
|
||||||
parser->setFeature ( XMLUni::fgXercesValidationErrorAsFatal, true );
|
|
||||||
parser->setFeature ( XMLUni::fgXercesLoadExternalDTD, true );
|
|
||||||
|
|
||||||
|
|
||||||
DefaultHandler handler;
|
|
||||||
MySAX2Handler mySAX2Handler;
|
|
||||||
parser->setContentHandler ( &handler );
|
|
||||||
parser->setErrorHandler ( &mySAX2Handler );
|
|
||||||
|
|
||||||
//DefaultHandler handler;
|
|
||||||
//parser->setEntityResolver ( &handler );
|
|
||||||
parser->setEntityResolver ( catalogResolver );
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
parser->parse ( (const XMLCh *) toString ( fileName ).GetData() );
|
|
||||||
}
|
|
||||||
catch ( XMLException& e )
|
|
||||||
{
|
|
||||||
delete parser;
|
|
||||||
lastError = toString ( e.getMessage() );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch ( SAXParseException& e )
|
|
||||||
{
|
|
||||||
delete parser;
|
|
||||||
lastError << _T ( "Validation stopped at line " )
|
|
||||||
<< e.getLineNumber() << _T ( ", column " ) << e.getColumnNumber()
|
|
||||||
<< _T ( ": " ) << toString ( e.getMessage() );
|
|
||||||
errorPosition = std::make_pair ( e.getLineNumber(), e.getColumnNumber() );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch ( ... )
|
|
||||||
{
|
|
||||||
delete parser;
|
|
||||||
lastError = _T ( "Unexpected validation error" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
delete parser;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tbd: cache grammar
|
// tbd: cache grammar
|
||||||
bool WrapXerces::validateMemory (
|
bool WrapXerces::validateMemory (
|
||||||
const char *buffer,
|
const char *utf8Buffer,
|
||||||
size_t len,
|
size_t len,
|
||||||
const wxString &system,
|
const wxString &fileName,
|
||||||
wxThread *thread /*= NULL*/ )
|
wxThread *thread /*= NULL*/,
|
||||||
|
bool forceGrammarCheck /*= true*/,
|
||||||
|
const wxChar *messageEOL /*= _T("[br]")*/)
|
||||||
{
|
{
|
||||||
|
#if 0 // Test DOM parser
|
||||||
|
std::auto_ptr<XercesDOMParser> parser ( new XercesDOMParser() );
|
||||||
|
|
||||||
|
parser->setDoNamespaces(true);
|
||||||
|
parser->setExitOnFirstFatalError(true);
|
||||||
|
parser->setValidationConstraintFatal(true);
|
||||||
|
//parser->setCreateEntityReferenceNodes(true); // Default is true
|
||||||
|
parser->setValidationScheme(XercesDOMParser::Val_Auto);
|
||||||
|
parser->setDoSchema(true);
|
||||||
|
parser->setValidationSchemaFullChecking(true);
|
||||||
|
parser->setCreateCommentNodes(false);
|
||||||
|
#else
|
||||||
std::auto_ptr<SAX2XMLReader> parser ( XMLReaderFactory::createXMLReader() );
|
std::auto_ptr<SAX2XMLReader> parser ( XMLReaderFactory::createXMLReader() );
|
||||||
|
|
||||||
parser->setFeature ( XMLUni::fgSAX2CoreNameSpaces, true );
|
parser->setFeature ( XMLUni::fgSAX2CoreNameSpaces, true );
|
||||||
parser->setFeature ( XMLUni::fgSAX2CoreValidation, true );
|
parser->setFeature ( XMLUni::fgSAX2CoreValidation, true );
|
||||||
parser->setFeature ( XMLUni::fgXercesDynamic, true );
|
parser->setFeature ( XMLUni::fgXercesDynamic, !forceGrammarCheck );
|
||||||
parser->setFeature ( XMLUni::fgXercesSchema, true );
|
parser->setFeature ( XMLUni::fgXercesSchema, true );
|
||||||
//parser->setFeature ( XMLUni::fgXercesSchemaFullChecking, true );
|
parser->setFeature ( XMLUni::fgXercesSchemaFullChecking, true);
|
||||||
parser->setFeature ( XMLUni::fgXercesValidationErrorAsFatal, true );
|
parser->setFeature ( XMLUni::fgXercesValidationErrorAsFatal, true );
|
||||||
parser->setFeature ( XMLUni::fgXercesLoadExternalDTD, true );
|
parser->setFeature ( XMLUni::fgXercesLoadExternalDTD, true );
|
||||||
|
|
||||||
DefaultHandler handler;
|
parser->setContentHandler ( &mySAX2Handler );
|
||||||
MySAX2Handler mySAX2Handler;
|
#endif
|
||||||
parser->setContentHandler ( &handler );
|
|
||||||
parser->setErrorHandler ( &mySAX2Handler );
|
parser->setErrorHandler ( &mySAX2Handler );
|
||||||
//parser->setEntityResolver ( &handler );
|
//parser->setEntityResolver ( &handler );
|
||||||
parser->setEntityResolver ( catalogResolver );
|
parser->setEntityResolver ( catalogResolver );
|
||||||
|
|
||||||
XMLByte* xmlBuffer = (XMLByte*) buffer;
|
mySAX2Handler.setEOL ( messageEOL );
|
||||||
MemBufInputSource source
|
|
||||||
( xmlBuffer
|
std::auto_ptr<InputSource> source;
|
||||||
, len
|
if ( utf8Buffer != NULL )
|
||||||
, ( const XMLCh * ) ( const char * ) system.mb_str ( getMBConv() )
|
{
|
||||||
);
|
source.reset ( new MemBufInputSource ( (XMLByte*) utf8Buffer, len,
|
||||||
|
(const XMLCh *) toString ( fileName ).GetData() ) );
|
||||||
|
wxString utf8 = _T("UTF-8");
|
||||||
|
source->setEncoding ( (const XMLCh *) toString ( utf8 ).GetData() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.reset ( new LocalFileInputSource (
|
||||||
|
(const XMLCh *) toString ( fileName ).GetData() ) );
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ( thread == NULL )
|
if ( thread == NULL )
|
||||||
{
|
{
|
||||||
parser->parse ( source );
|
parser->parse ( *source );
|
||||||
}
|
}
|
||||||
else if ( !thread->TestDestroy() )
|
else if ( !thread->TestDestroy() )
|
||||||
{
|
{
|
||||||
XMLPScanToken token;
|
XMLPScanToken token;
|
||||||
if ( parser->parseFirst ( source, token ) )
|
if ( parser->parseFirst ( *source, token ) )
|
||||||
while ( (!thread->TestDestroy()) && parser->parseNext ( token ) )
|
while ( (!thread->TestDestroy()) && parser->parseNext ( token ) )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( XMLException& e )
|
catch ( XMLException& e )
|
||||||
{
|
{
|
||||||
lastError = wxEmptyString;
|
wxString error = toString ( e.getMessage() );
|
||||||
|
int i = error.Find( _T("Message:") );
|
||||||
|
if ( i != wxNOT_FOUND )
|
||||||
|
error = error.substr( i );
|
||||||
|
mySAX2Handler.getErrors() << error;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch ( SAXParseException& e )
|
catch ( SAXParseException& e )
|
||||||
{
|
{
|
||||||
lastError << _T ( "Ln " ) << e.getLineNumber() << _T ( " Col " )
|
// It has already been processed in mySAX2Handler
|
||||||
<< e.getColumnNumber() << _T ( ": " ) << toString ( e.getMessage() );
|
|
||||||
errorPosition = std::make_pair ( e.getLineNumber(), e.getColumnNumber() );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch ( ... )
|
catch ( ... )
|
||||||
{
|
{
|
||||||
if ( thread != NULL && thread->TestDestroy() )
|
if ( thread != NULL && thread->TestDestroy() )
|
||||||
throw;
|
throw;
|
||||||
lastError = wxEmptyString;
|
mySAX2Handler.getErrors() << _("Unexpected validation error");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wxString &WrapXerces::getLastError()
|
return mySAX2Handler.getErrors().empty();
|
||||||
{
|
|
||||||
int i = lastError.Find( _T ( "Message:" ) );
|
|
||||||
if ( i != wxNOT_FOUND )
|
|
||||||
{
|
|
||||||
lastError = lastError.substr( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastError;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<int, int> WrapXerces::getErrorPosition()
|
|
||||||
{
|
|
||||||
return errorPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxMBConv &WrapXerces::getMBConv()
|
const wxMBConv &WrapXerces::getMBConv()
|
||||||
|
@ -240,3 +205,20 @@ wxMemoryBuffer WrapXerces::toString ( const wxString &str )
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MySAX2Handler::logError ( const wxString &type, wxLogLevelValues level,
|
||||||
|
const SAXParseException& e )
|
||||||
|
{
|
||||||
|
mErrors << wxString::Format (
|
||||||
|
_("%s at line %llu, column %llu: %s%s"),
|
||||||
|
type.c_str(), e.getLineNumber(), e.getColumnNumber(),
|
||||||
|
WrapXerces::toString ( e.getMessage() ).c_str(), mEOL.c_str() );
|
||||||
|
|
||||||
|
// Only save the first warning position
|
||||||
|
if ( level > mLevel || ( level == mLevel && mErrorPosition.first == 1
|
||||||
|
&& mErrorPosition.second == 1 ) )
|
||||||
|
{
|
||||||
|
mErrorPosition.first = e.getLineNumber();
|
||||||
|
mErrorPosition.second = e.getColumnNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <wx/wx.h>
|
#include <wx/wx.h>
|
||||||
#include <wx/strconv.h>
|
#include <wx/strconv.h>
|
||||||
#include <wx/buffer.h>
|
#include <wx/buffer.h>
|
||||||
|
#include <wx/log.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
|
@ -37,6 +38,58 @@
|
||||||
|
|
||||||
using namespace xercesc;
|
using namespace xercesc;
|
||||||
|
|
||||||
|
class MySAX2Handler : public DefaultHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MySAX2Handler()
|
||||||
|
{
|
||||||
|
mEOL = "\n";
|
||||||
|
resetErrors();
|
||||||
|
}
|
||||||
|
void error ( const SAXParseException& e )
|
||||||
|
{
|
||||||
|
logError ( _("Error"), wxLOG_Error, e );
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
void warning ( const SAXParseException& e )
|
||||||
|
{
|
||||||
|
logError ( _("Warning"), wxLOG_Warning, e );
|
||||||
|
}
|
||||||
|
void fatalError ( const SAXParseException& e )
|
||||||
|
{
|
||||||
|
logError ( _("FatalError"), wxLOG_FatalError, e );
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
void resetErrors()
|
||||||
|
{
|
||||||
|
mErrors.clear();
|
||||||
|
mErrorPosition = std::make_pair ( 1, 1 );
|
||||||
|
}
|
||||||
|
const wxString &getErrors() const
|
||||||
|
{
|
||||||
|
return mErrors;
|
||||||
|
}
|
||||||
|
wxString &getErrors()
|
||||||
|
{
|
||||||
|
return mErrors;
|
||||||
|
}
|
||||||
|
const std::pair<int, int> &getErrorPosition() const
|
||||||
|
{
|
||||||
|
return mErrorPosition;
|
||||||
|
}
|
||||||
|
void logError ( const wxString &type, wxLogLevelValues level,
|
||||||
|
const SAXParseException& e );
|
||||||
|
void setEOL ( const wxChar *eol )
|
||||||
|
{
|
||||||
|
mEOL = eol;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
wxString mErrors;
|
||||||
|
std::pair<int, int> mErrorPosition;
|
||||||
|
wxLogLevelValues mLevel;
|
||||||
|
wxString mEOL;
|
||||||
|
};
|
||||||
|
|
||||||
class WrapXerces : private boost::noncopyable
|
class WrapXerces : private boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -44,10 +97,19 @@ class WrapXerces : private boost::noncopyable
|
||||||
WrapXerces();
|
WrapXerces();
|
||||||
virtual ~WrapXerces();
|
virtual ~WrapXerces();
|
||||||
bool validate ( const wxString &fileName );
|
bool validate ( const wxString &fileName );
|
||||||
bool validateMemory ( const char *buffer, size_t len,
|
bool validateMemory ( const char *utf8Buffer, size_t len,
|
||||||
const wxString &system, wxThread *thread = NULL );
|
const wxString &fileName, wxThread *thread = NULL,
|
||||||
const wxString &getLastError();
|
bool forceGrammarCheck = true, /* Must specify a grammar */
|
||||||
std::pair<int, int> getErrorPosition();
|
const wxChar *messageEOL = _T("[br]") );
|
||||||
|
const wxString &getLastError()
|
||||||
|
{
|
||||||
|
return mySAX2Handler.getErrors();
|
||||||
|
}
|
||||||
|
const std::pair<int, int> &getErrorPosition()
|
||||||
|
{
|
||||||
|
return mySAX2Handler.getErrorPosition();
|
||||||
|
}
|
||||||
|
|
||||||
static wxString toString ( const XMLCh *str );
|
static wxString toString ( const XMLCh *str );
|
||||||
// Convert Unicode string to const XMLCh *
|
// Convert Unicode string to const XMLCh *
|
||||||
//#if wxCHECK_VERSION(2,9,0)
|
//#if wxCHECK_VERSION(2,9,0)
|
||||||
|
@ -60,21 +122,7 @@ class WrapXerces : private boost::noncopyable
|
||||||
static const wxMBConv &getMBConv();
|
static const wxMBConv &getMBConv();
|
||||||
|
|
||||||
XercesCatalogResolver *catalogResolver;
|
XercesCatalogResolver *catalogResolver;
|
||||||
wxString lastError;
|
MySAX2Handler mySAX2Handler;
|
||||||
std::pair<int, int> errorPosition;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MySAX2Handler : public DefaultHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void error ( const SAXParseException& e )
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
void warning ( const SAXParseException& e )
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3922,32 +3922,14 @@ void MyFrame::OnValidateSchema ( wxCommandEvent& event )
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wxString fileName;
|
|
||||||
fileName = doc->getFullFileName();
|
|
||||||
|
|
||||||
WrapTempFileName wtfn ( fileName );
|
|
||||||
if ( fileName.empty() || doc->GetModify() )
|
|
||||||
{
|
|
||||||
wxString wideBuffer = doc->GetText();
|
|
||||||
|
|
||||||
std::string buffer = ( const char * ) wideBuffer.mb_str ( wxConvUTF8 );
|
|
||||||
if ( !saveRawUtf8 (
|
|
||||||
wtfn.name(),
|
|
||||||
buffer ) )
|
|
||||||
{
|
|
||||||
messagePane (
|
|
||||||
_ ( "Cannot save temporary copy for validation; please save or discard changes" ),
|
|
||||||
CONST_STOP );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fileName = wtfn.wideName();
|
|
||||||
}
|
|
||||||
|
|
||||||
statusProgress ( _ ( "Validation in progress..." ) );
|
statusProgress ( _ ( "Validation in progress..." ) );
|
||||||
doc->clearErrorIndicators();
|
doc->clearErrorIndicators();
|
||||||
|
|
||||||
|
wxString fileName = doc->getFullFileName();
|
||||||
|
wxString utf8Buffer = doc->myGetTextRaw();
|
||||||
std::auto_ptr<WrapXerces> validator ( new WrapXerces() );
|
std::auto_ptr<WrapXerces> validator ( new WrapXerces() );
|
||||||
if ( !validator->validate ( fileName ) )
|
if ( !validator->validateMemory ( utf8Buffer.c_str(), utf8Buffer.size(),
|
||||||
|
fileName ) )
|
||||||
{
|
{
|
||||||
statusProgress ( wxEmptyString );
|
statusProgress ( wxEmptyString );
|
||||||
messagePane ( validator->getLastError(), CONST_WARNING );
|
messagePane ( validator->getLastError(), CONST_WARNING );
|
||||||
|
|
Loading…
Reference in New Issue