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 "validationthread.h"
|
||||
#include "wrapxerces.h"
|
||||
|
@ -42,7 +43,11 @@ void *ValidationThread::Entry()
|
|||
myBuffer.c_str(),
|
||||
myBuffer.size(),
|
||||
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();
|
||||
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
|
||||
#include "wrapxerces.h"
|
||||
|
||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||
#include <xercesc/sax2/XMLReaderFactory.hpp>
|
||||
#include <xercesc/sax2/SAX2XMLReader.hpp>
|
||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||
#include <xercesc/util/XMLUni.hpp>
|
||||
#include <xercesc/framework/MemBufInputSource.hpp>
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
|
@ -51,7 +53,6 @@ WrapXerces::WrapXerces()
|
|||
{
|
||||
WrapXerces::Init();
|
||||
|
||||
errorPosition = std::make_pair ( 1, 1 );
|
||||
catalogResolver = new XercesCatalogResolver();
|
||||
}
|
||||
|
||||
|
@ -62,135 +63,99 @@ WrapXerces::~WrapXerces()
|
|||
|
||||
bool WrapXerces::validate ( const wxString& fileName )
|
||||
{
|
||||
SAX2XMLReader *parser = XMLReaderFactory::createXMLReader();
|
||||
return validateMemory ( NULL, 0, fileName );
|
||||
}
|
||||
|
||||
// tbd: cache grammar
|
||||
bool WrapXerces::validateMemory (
|
||||
const char *utf8Buffer,
|
||||
size_t len,
|
||||
const wxString &fileName,
|
||||
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() );
|
||||
|
||||
parser->setFeature ( XMLUni::fgSAX2CoreNameSpaces, true );
|
||||
parser->setFeature ( XMLUni::fgSAX2CoreValidation, true );
|
||||
parser->setFeature ( XMLUni::fgXercesDynamic, false );
|
||||
parser->setFeature ( XMLUni::fgXercesDynamic, !forceGrammarCheck );
|
||||
parser->setFeature ( XMLUni::fgXercesSchema, true );
|
||||
parser->setFeature ( XMLUni::fgXercesSchemaFullChecking, true);
|
||||
parser->setFeature ( XMLUni::fgXercesValidationErrorAsFatal, true );
|
||||
parser->setFeature ( XMLUni::fgXercesLoadExternalDTD, true );
|
||||
|
||||
parser->setContentHandler ( &mySAX2Handler );
|
||||
#endif
|
||||
|
||||
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
|
||||
bool WrapXerces::validateMemory (
|
||||
const char *buffer,
|
||||
size_t len,
|
||||
const wxString &system,
|
||||
wxThread *thread /*= NULL*/ )
|
||||
{
|
||||
std::auto_ptr<SAX2XMLReader> parser ( XMLReaderFactory::createXMLReader() );
|
||||
|
||||
parser->setFeature ( XMLUni::fgSAX2CoreNameSpaces, true );
|
||||
parser->setFeature ( XMLUni::fgSAX2CoreValidation, true );
|
||||
parser->setFeature ( XMLUni::fgXercesDynamic, true );
|
||||
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 );
|
||||
//parser->setEntityResolver ( &handler );
|
||||
parser->setEntityResolver ( catalogResolver );
|
||||
|
||||
XMLByte* xmlBuffer = (XMLByte*) buffer;
|
||||
MemBufInputSource source
|
||||
( xmlBuffer
|
||||
, len
|
||||
, ( const XMLCh * ) ( const char * ) system.mb_str ( getMBConv() )
|
||||
);
|
||||
mySAX2Handler.setEOL ( messageEOL );
|
||||
|
||||
std::auto_ptr<InputSource> source;
|
||||
if ( utf8Buffer != NULL )
|
||||
{
|
||||
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
|
||||
{
|
||||
if ( thread == NULL )
|
||||
{
|
||||
parser->parse ( source );
|
||||
parser->parse ( *source );
|
||||
}
|
||||
else if ( !thread->TestDestroy() )
|
||||
{
|
||||
XMLPScanToken token;
|
||||
if ( parser->parseFirst ( source, token ) )
|
||||
if ( parser->parseFirst ( *source, token ) )
|
||||
while ( (!thread->TestDestroy()) && parser->parseNext ( token ) )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
catch ( SAXParseException& e )
|
||||
{
|
||||
lastError << _T ( "Ln " ) << e.getLineNumber() << _T ( " Col " )
|
||||
<< e.getColumnNumber() << _T ( ": " ) << toString ( e.getMessage() );
|
||||
errorPosition = std::make_pair ( e.getLineNumber(), e.getColumnNumber() );
|
||||
// It has already been processed in mySAX2Handler
|
||||
return false;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
if ( thread != NULL && thread->TestDestroy() )
|
||||
throw;
|
||||
lastError = wxEmptyString;
|
||||
mySAX2Handler.getErrors() << _("Unexpected validation error");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const wxString &WrapXerces::getLastError()
|
||||
{
|
||||
int i = lastError.Find( _T ( "Message:" ) );
|
||||
if ( i != wxNOT_FOUND )
|
||||
{
|
||||
lastError = lastError.substr( i );
|
||||
}
|
||||
|
||||
return lastError;
|
||||
}
|
||||
|
||||
std::pair<int, int> WrapXerces::getErrorPosition()
|
||||
{
|
||||
return errorPosition;
|
||||
return mySAX2Handler.getErrors().empty();
|
||||
}
|
||||
|
||||
const wxMBConv &WrapXerces::getMBConv()
|
||||
|
@ -240,3 +205,20 @@ wxMemoryBuffer WrapXerces::toString ( const wxString &str )
|
|||
|
||||
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/strconv.h>
|
||||
#include <wx/buffer.h>
|
||||
#include <wx/log.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <boost/utility.hpp>
|
||||
|
@ -37,6 +38,58 @@
|
|||
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -44,10 +97,19 @@ class WrapXerces : private boost::noncopyable
|
|||
WrapXerces();
|
||||
virtual ~WrapXerces();
|
||||
bool validate ( const wxString &fileName );
|
||||
bool validateMemory ( const char *buffer, size_t len,
|
||||
const wxString &system, wxThread *thread = NULL );
|
||||
const wxString &getLastError();
|
||||
std::pair<int, int> getErrorPosition();
|
||||
bool validateMemory ( const char *utf8Buffer, size_t len,
|
||||
const wxString &fileName, wxThread *thread = NULL,
|
||||
bool forceGrammarCheck = true, /* Must specify a grammar */
|
||||
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 );
|
||||
// Convert Unicode string to const XMLCh *
|
||||
//#if wxCHECK_VERSION(2,9,0)
|
||||
|
@ -60,21 +122,7 @@ class WrapXerces : private boost::noncopyable
|
|||
static const wxMBConv &getMBConv();
|
||||
|
||||
XercesCatalogResolver *catalogResolver;
|
||||
wxString lastError;
|
||||
std::pair<int, int> errorPosition;
|
||||
};
|
||||
|
||||
class MySAX2Handler : public DefaultHandler
|
||||
{
|
||||
public:
|
||||
void error ( const SAXParseException& e )
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
void warning ( const SAXParseException& e )
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
MySAX2Handler mySAX2Handler;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3922,32 +3922,14 @@ void MyFrame::OnValidateSchema ( wxCommandEvent& event )
|
|||
}
|
||||
#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..." ) );
|
||||
doc->clearErrorIndicators();
|
||||
|
||||
wxString fileName = doc->getFullFileName();
|
||||
wxString utf8Buffer = doc->myGetTextRaw();
|
||||
std::auto_ptr<WrapXerces> validator ( new WrapXerces() );
|
||||
if ( !validator->validate ( fileName ) )
|
||||
if ( !validator->validateMemory ( utf8Buffer.c_str(), utf8Buffer.size(),
|
||||
fileName ) )
|
||||
{
|
||||
statusProgress ( wxEmptyString );
|
||||
messagePane ( validator->getLastError(), CONST_WARNING );
|
||||
|
|
Loading…
Reference in New Issue