xml-copy-editor-code/src/xmlpromptgenerator.cpp

676 lines
18 KiB
C++
Raw Normal View History

2009-11-06 18:06:12 +01:00
/*
* Copyright 2005-2007 Gerald Schmidt.
*
* This file is part of Xml Copy Editor.
*
* Xml Copy Editor is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* Xml Copy Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Xml Copy Editor; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <wx/wx.h>
#include <wx/filename.h>
#include <wx/filesys.h>
2009-11-06 18:06:12 +01:00
#include <stdexcept>
#include "xmlpromptgenerator.h"
#include "xmlencodinghandler.h"
#include "readfile.h"
#include "replace.h"
#include "pathresolver.h"
2014-04-24 14:14:29 +02:00
#include "threadreaper.h"
2009-11-06 18:06:12 +01:00
#undef XMLCALL
#include "catalogresolver.h"
// Xerces-C req'd for Schema parsing
#include "wrapxerces.h" // Declaration of toString() and XERCES_TMPLSINC definition
2009-11-06 18:06:12 +01:00
#include <xercesc/util/NameIdPool.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/XMLValidator.hpp>
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/validators/schema/SchemaValidator.hpp>
#include <xercesc/validators/common/ContentSpecNode.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
#include <xercesc/framework/URLInputSource.hpp>
#include <xercesc/validators/DTD/DTDGrammar.hpp>
2009-11-06 18:06:12 +01:00
using namespace xercesc;
2014-04-24 14:14:29 +02:00
extern wxCriticalSection xmlcopyeditorCriticalSection;
DEFINE_EVENT_TYPE ( myEVT_NOTIFY_PROMPT_GENERATED );
2009-11-06 18:06:12 +01:00
XmlPromptGenerator::XmlPromptGenerator (
2014-04-24 14:14:29 +02:00
wxEvtHandler *handler,
const char *buffer,
size_t bufferSize,
const wxString& basePath,
2014-04-13 17:16:04 +02:00
const wxString& auxPath,
const char *encoding
)
: WrapExpat ( encoding )
2014-04-24 14:14:29 +02:00
, wxThread ( wxTHREAD_JOINABLE )
2014-04-13 17:16:04 +02:00
, d ( new PromptGeneratorData() )
2014-04-24 14:14:29 +02:00
, mEventHandler ( handler )
, mBuffer ( buffer, bufferSize )
, mStopping ( false )
2009-11-06 18:06:12 +01:00
{
2014-04-24 14:14:29 +02:00
if ( mBuffer.length() != bufferSize )
throw std::bad_alloc();
XML_SetUserData ( p, this );
2009-11-06 18:06:12 +01:00
d->p = p;
d->basePath = basePath;
d->auxPath = auxPath;
d->isRootElement = true;
d->grammarFound = false;
d->attributeValueCutoff = 12; // this prevents enums being stored in their thousands
XML_SetParamEntityParsing ( p, XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE );
XML_SetElementHandler ( p, starthandler, endhandler );
XML_SetDoctypeDeclHandler ( p, doctypedeclstarthandler, doctypedeclendhandler );
XML_SetElementDeclHandler ( p, elementdeclhandler );
XML_SetAttlistDeclHandler ( p, attlistdeclhandler );
XML_SetEntityDeclHandler ( p, entitydeclhandler );
2014-04-24 14:14:29 +02:00
XML_SetExternalEntityRefHandlerArg ( p, this );
2009-11-06 18:06:12 +01:00
XML_SetExternalEntityRefHandler ( p, externalentityrefhandler );
XML_SetBase ( p, d->basePath.utf8_str() );
2009-11-06 18:06:12 +01:00
if ( !auxPath.empty() )
XML_UseForeignDTD ( p, true );
}
XmlPromptGenerator::~XmlPromptGenerator()
{}
void XMLCALL XmlPromptGenerator::starthandler (
void *data,
const XML_Char *el,
const XML_Char **attr )
{
2014-04-24 14:14:29 +02:00
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) data;
PromptGeneratorData *d = pThis->d.get();
2009-11-06 18:06:12 +01:00
if (d->isRootElement)
{
d->rootElement = el;
2014-04-24 14:14:29 +02:00
pThis->handleSchema ( d, el, attr ); // experimental: schema has been pre-parsed
2009-11-06 18:06:12 +01:00
d->isRootElement = false;
2014-04-24 14:14:29 +02:00
if ( d->grammarFound || pThis->TestDestroy() )//if ( d->elementMap.size() == 1) // must be 1 for success
2009-11-06 18:06:12 +01:00
{
return;
}
}
d->push ( el );
wxString parent ( d->getParent().c_str(), wxConvUTF8 );
wxString element ( el, wxConvUTF8 );
2009-11-06 18:06:12 +01:00
// update elementMap
d->elementMap[parent].insert ( element );
2009-11-06 18:06:12 +01:00
wxString attributeName, attributeValue;
2009-11-06 18:06:12 +01:00
// update attributeMap
for ( ; *attr; attr += 2 )
{
attributeName = wxString ( *attr, wxConvUTF8 );
attributeValue = wxString ( * ( attr + 1 ), wxConvUTF8 );
2009-11-06 18:06:12 +01:00
if (d->attributeMap[element][attributeName].size() < d->attributeValueCutoff)
d->attributeMap[element][attributeName].insert ( attributeValue );
}
}
void XMLCALL XmlPromptGenerator::endhandler ( void *data, const XML_Char *el )
{
2014-04-24 14:14:29 +02:00
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) data;
2009-11-06 18:06:12 +01:00
2014-04-24 14:14:29 +02:00
if ( pThis->TestDestroy() )
XML_StopParser ( pThis->d->p, false );
else
pThis->d->pop();
2009-11-06 18:06:12 +01:00
}
// handlers for DOCTYPE handling
void XMLCALL XmlPromptGenerator::doctypedeclstarthandler (
void *data,
const XML_Char *doctypeName,
const XML_Char *sysid,
const XML_Char *pubid,
int has_internal_subset )
{
2013-11-12 17:30:07 +01:00
//PromptGeneratorData *d;
//d = ( PromptGeneratorData * ) data;
2009-11-06 18:06:12 +01:00
}
void XMLCALL XmlPromptGenerator::doctypedeclendhandler ( void *data )
{
2014-04-24 14:14:29 +02:00
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) data;
PromptGeneratorData *d = pThis->d.get();
2009-11-06 18:06:12 +01:00
if ( !d->elementMap.empty() )
{
d->grammarFound = true;
XML_StopParser ( d->p, false ); // experimental
}
2014-04-24 14:14:29 +02:00
if ( pThis->TestDestroy() )
XML_StopParser ( d->p, false );
2009-11-06 18:06:12 +01:00
}
void XMLCALL XmlPromptGenerator::elementdeclhandler (
void *data,
const XML_Char *name,
XML_Content *model )
{
2014-04-24 14:14:29 +02:00
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) data;
PromptGeneratorData *d = pThis->d.get();
2009-11-06 18:06:12 +01:00
wxString myElement ( name, wxConvUTF8 );
2009-11-06 18:06:12 +01:00
2014-04-24 14:14:29 +02:00
pThis->getContent ( *model, d->elementStructureMap[myElement],
d->elementMap[myElement] );
XML_FreeContentModel ( d->p, model );
2014-04-24 14:14:29 +02:00
if ( pThis->TestDestroy() )
XML_StopParser ( d->p, false );
}
void XmlPromptGenerator::getContent (
const XML_Content &content,
wxString &contentModel,
std::set<wxString> &list )
{
2014-04-24 14:14:29 +02:00
if ( TestDestroy() )
return;
wxString name;
switch ( content.type )
2009-11-06 18:06:12 +01:00
{
case XML_CTYPE_EMPTY:
contentModel += _T("EMPTY");
return;
case XML_CTYPE_ANY:
contentModel += _T("ANY");
return;
case XML_CTYPE_NAME:
name = wxString ( content.name, wxConvUTF8 );
list.insert ( name );
contentModel += name;
break;
case XML_CTYPE_CHOICE:
case XML_CTYPE_SEQ:
case XML_CTYPE_MIXED:
default:
wxString sep;
sep = ( content.type == XML_CTYPE_CHOICE ) ? _T("|") : _T(",");
contentModel += ( content.type == XML_CTYPE_MIXED ) ? _T("(#PCDATA|") : _T("(");
for ( unsigned i = 0; i < content.numchildren; i++ )
2009-11-06 18:06:12 +01:00
{
if ( i > 0 )
contentModel += sep;
getContent ( content.children[i], contentModel, list);
2009-11-06 18:06:12 +01:00
}
contentModel += _T(")");
break;
2009-11-06 18:06:12 +01:00
}
switch ( content.quant )
2009-11-06 18:06:12 +01:00
{
case XML_CQUANT_OPT:
contentModel += _T("?");
break;
case XML_CQUANT_REP:
contentModel += _T("*");
break;
case XML_CQUANT_PLUS:
contentModel += _T("+");
break;
case XML_CQUANT_NONE:
default:
break;
2009-11-06 18:06:12 +01:00
}
}
void XMLCALL XmlPromptGenerator::attlistdeclhandler (
void *data,
const XML_Char *elname,
const XML_Char *attname,
const XML_Char *att_type,
const XML_Char *dflt,
int isrequired )
{
2014-04-24 14:14:29 +02:00
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) data;
PromptGeneratorData *d = pThis->d.get();
2009-11-06 18:06:12 +01:00
wxString element ( elname, wxConvUTF8 );
wxString attribute ( attname, wxConvUTF8 );
std::set<wxString> &attributeValues = d->attributeMap[element][attribute];
2009-11-06 18:06:12 +01:00
if ( *att_type == '(' ) // change to exclude _known_ identifiers?
{
2012-08-06 17:27:22 +02:00
const char *s, *word;
s = att_type;
2009-11-06 18:06:12 +01:00
do {
s++;
word = s;
2012-08-06 17:27:22 +02:00
while ( *s != '|' && *s != ')' )
s++;
wxString currentValue ( word, wxConvUTF8, s - word );
2009-11-06 18:06:12 +01:00
attributeValues.insert ( currentValue );
while ( *s != '|' && *s != ')')
s++;
2012-08-06 17:27:22 +02:00
} while ( *s != ')' );
2009-11-06 18:06:12 +01:00
}
if ( isrequired )
{
d->requiredAttributeMap[element].insert ( attribute );
2009-11-06 18:06:12 +01:00
}
2014-04-24 14:14:29 +02:00
if ( pThis->TestDestroy() )
XML_StopParser ( d->p, false );
2009-11-06 18:06:12 +01:00
}
int XMLCALL XmlPromptGenerator::externalentityrefhandler (
XML_Parser p,
const XML_Char *context,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId )
{
2014-04-24 14:14:29 +02:00
// arg is set to user data in c'tor
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) p;
PromptGeneratorData *d = pThis->d.get();
2009-11-06 18:06:12 +01:00
// 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;
parser.setDoNamespaces ( true );
parser.setDoSchema ( true );
parser.setValidationSchemaFullChecking ( true );
MySAX2Handler handler;
XercesCatalogResolver catalogResolver;
parser.setErrorHandler ( &handler );
parser.setEntityResolver ( &catalogResolver );
wxString wideSystemId ( systemId, wxConvUTF8 ); // TODO: Apply encoding
wxString widePublicId ( publicId, wxConvUTF8 );
std::auto_ptr<InputSource> source ( catalogResolver.resolveEntity
( ( const XMLCh * ) WrapXerces::toString ( widePublicId ).GetData()
, ( const XMLCh * ) WrapXerces::toString ( wideSystemId ).GetData()
) );
if ( !source.get() )
{
wxString fileURL = wxFileSystem::FileNameToURL ( d->basePath );
source.reset ( new URLInputSource
( ( const XMLCh * ) WrapXerces::toString ( fileURL ).GetData()
, ( const XMLCh * ) WrapXerces::toString ( wideSystemId ).GetData()
, ( const XMLCh * ) WrapXerces::toString ( widePublicId ).GetData()
) );
}
if ( pThis->TestDestroy() )
return XML_STATUS_ERROR;
Grammar *rootGrammar;
try {
rootGrammar = parser.loadGrammar ( *source, Grammar::DTDGrammarType );
if ( !rootGrammar )
return XML_STATUS_ERROR;
}
catch ( SAXParseException& e )
{
wxLogError ( _T ( "%s" ), handler.getErrors().c_str() );
return XML_STATUS_ERROR;
}
DTDGrammar* grammar = ( DTDGrammar* ) rootGrammar;
NameIdPoolEnumerator<DTDElementDecl> elemEnum = grammar->getElemEnumerator();
SubstitutionMap substitutions;
2014-04-24 14:14:29 +02:00
while ( elemEnum.hasMoreElements() && !pThis->TestDestroy() )
{
const DTDElementDecl& curElem = elemEnum.nextElement();
2014-04-24 14:14:29 +02:00
pThis->buildElementPrompt ( d, &curElem, substitutions );
}
2014-04-24 14:14:29 +02:00
return pThis->TestDestroy() ? XML_STATUS_ERROR : XML_STATUS_OK;
#else // !PREFER_EXPAT_TO_XERCES_C
2012-08-27 14:25:08 +02:00
int ret;
2009-11-06 18:06:12 +01:00
std::string buffer;
// auxPath req'd?
if ( !systemId && !publicId )
{
ReadFile::run ( ( const char * ) d->auxPath.mb_str(), buffer );
2009-11-06 18:06:12 +01:00
if ( buffer.empty() )
{
2012-08-27 14:25:08 +02:00
return XML_STATUS_ERROR;
2009-11-06 18:06:12 +01:00
}
d->encoding = XmlEncodingHandler::get ( buffer );
XML_Parser dtdParser = XML_ExternalEntityParserCreate ( d->p, context, d->encoding.c_str() );
2014-04-24 14:14:29 +02:00
if ( pThis->TestDestroy() || !dtdParser )
2012-08-27 14:25:08 +02:00
return XML_STATUS_ERROR;
XML_SetBase ( dtdParser, d->auxPath.utf8_str() );
2012-08-27 14:25:08 +02:00
ret = XML_Parse ( dtdParser, buffer.c_str(), buffer.size(), true );
XML_ParserFree ( dtdParser );
return ret;
2009-11-06 18:06:12 +01:00
}
2013-10-26 15:15:42 +02:00
wxString widePublicId ( publicId, wxConvUTF8 );
wxString wideSystemId ( systemId, wxConvUTF8 );
CatalogResolver cr;
2013-10-26 15:15:42 +02:00
wideSystemId = cr.catalogResolve ( widePublicId, wideSystemId );
2013-10-26 15:15:42 +02:00
if ( wideSystemId.empty() )
2009-11-06 18:06:12 +01:00
{
if ( systemId )
2013-10-26 15:15:42 +02:00
wideSystemId = wxString ( systemId, wxConvUTF8 );
2009-11-06 18:06:12 +01:00
if ( base )
{
2013-10-26 15:15:42 +02:00
wxString test = PathResolver::run ( wideSystemId,
wxString ( base, wxConvUTF8 ) );
2009-11-06 18:06:12 +01:00
if ( !test.empty() )
{
2013-10-26 15:15:42 +02:00
wideSystemId = test;
2009-11-06 18:06:12 +01:00
}
}
}
2013-10-26 15:15:42 +02:00
std::string localName;
localName = wideSystemId.mb_str ( wxConvLocal );
if ( !localName.empty() )
2009-11-06 18:06:12 +01:00
{
2013-10-26 15:15:42 +02:00
ReadFile::run ( localName, buffer );
2009-11-06 18:06:12 +01:00
}
std::string encoding = XmlEncodingHandler::get ( buffer );
XML_Parser dtdParser = XML_ExternalEntityParserCreate ( d->p, context, encoding.c_str() );
2014-04-24 14:14:29 +02:00
if ( pThis->TestDestroy() || !dtdParser )
2012-08-27 14:25:08 +02:00
return XML_STATUS_ERROR;
2009-11-06 18:06:12 +01:00
2013-10-26 15:15:42 +02:00
XML_SetBase ( dtdParser, wideSystemId.utf8_str() );
2009-11-06 18:06:12 +01:00
2012-08-27 14:25:08 +02:00
ret = XML_Parse ( dtdParser, buffer.c_str(), buffer.size(), true );
XML_ParserFree ( dtdParser );
2014-04-24 14:14:29 +02:00
return pThis->TestDestroy() ? XML_STATUS_ERROR : ret;
#endif // PREFER_EXPAT_TO_XERCES_C
2009-11-06 18:06:12 +01:00
}
void XMLCALL XmlPromptGenerator::entitydeclhandler (
void *data,
const XML_Char *entityName,
int is_parameter_entity,
const XML_Char *value,
int value_length,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId,
const XML_Char *notationName )
{
2014-04-24 14:14:29 +02:00
// arg is set to user data in c'tor
XmlPromptGenerator *pThis = ( XmlPromptGenerator * ) data;
PromptGeneratorData *d = pThis->d.get();
2009-11-06 18:06:12 +01:00
if (
entityName &&
!is_parameter_entity &&
!systemId &&
!publicId &&
!notationName )
{
d->entitySet.insert ( wxString ( entityName, wxConvUTF8 ) );
2009-11-06 18:06:12 +01:00
}
2014-04-24 14:14:29 +02:00
if ( pThis->TestDestroy() )
XML_StopParser ( d->p, false );
2009-11-06 18:06:12 +01:00
}
void XmlPromptGenerator::handleSchema (
PromptGeneratorData *d,
const XML_Char *el,
const XML_Char **attr )
{
if ( !d->isRootElement )
return;
2009-11-06 18:06:12 +01:00
// first check for XML Schema association
2012-08-11 11:12:28 +02:00
const char **schemaAttr = ( const char ** ) attr; // now redundant; could use attr
wxString path;
for ( ; *schemaAttr; schemaAttr += 2 )
2009-11-06 18:06:12 +01:00
{
// no namespace
if ( !strcmp ( *schemaAttr, "xsi:noNamespaceSchemaLocation" ) )
2009-11-06 18:06:12 +01:00
{
path = wxString ( schemaAttr[1], wxConvUTF8 );
2009-11-06 18:06:12 +01:00
break;
}
// with namespace -- check if this works
else if ( !strcmp ( *schemaAttr, "xsi:schemaLocation" ) )
2009-11-06 18:06:12 +01:00
{
const char *searchIterator = * ( schemaAttr + 1 );
while ( *searchIterator && *searchIterator != ' ' && *searchIterator != '\t' && *searchIterator != '\n' )
searchIterator++;
2009-11-06 18:06:12 +01:00
if ( *searchIterator )
{
path = wxString ( searchIterator + 1, wxConvUTF8 );
2009-11-06 18:06:12 +01:00
break;
}
}
}
if ( path.empty() )
{
return;
}
wxString schemaPath = PathResolver::run ( path, ( d->auxPath.empty() ) ? d->basePath : d->auxPath);
2009-11-06 18:06:12 +01:00
std::auto_ptr<XercesDOMParser> parser ( new XercesDOMParser() );
2009-11-06 18:06:12 +01:00
parser->setDoNamespaces ( true );
parser->setDoSchema ( true );
parser->setValidationSchemaFullChecking ( true );
2014-04-24 14:14:29 +02:00
if ( TestDestroy() )
{
XML_StopParser ( d->p, false );
return;
}
Grammar *rootGrammar = parser->loadGrammar
2013-10-25 13:23:34 +02:00
( ( const XMLCh * ) WrapXerces::toString ( schemaPath ).GetData()
, Grammar::SchemaGrammarType
);
2009-11-06 18:06:12 +01:00
if ( !rootGrammar )
{
return;
2009-11-06 18:06:12 +01:00
}
SchemaGrammar* grammar = ( SchemaGrammar* ) rootGrammar;
RefHash3KeysIdPoolEnumerator<SchemaElementDecl> elemEnum = grammar->getElemEnumerator();
if ( !elemEnum.hasMoreElements() )
{
return;
}
SubstitutionMap substitutions;
buildSubstitutionMap ( substitutions, *grammar );
2014-04-24 14:14:29 +02:00
while ( elemEnum.hasMoreElements() && !TestDestroy() )
2009-11-06 18:06:12 +01:00
{
const SchemaElementDecl& curElem = elemEnum.nextElement();
buildElementPrompt ( d, &curElem, substitutions );
}
2009-11-06 18:06:12 +01:00
d->grammarFound = true;
XML_StopParser ( d->p, false );
}
void XmlPromptGenerator::buildElementPrompt (
PromptGeneratorData *d,
const XMLElementDecl *element,
SubstitutionMap &substitutions )
{
2009-11-06 18:06:12 +01:00
wxString name;
const QName *qnm = element->getElementName();
if ( qnm == NULL )
return;
name = WrapXerces::toString ( qnm->getRawName() ); // this includes any prefix:localname combinations
if ( name.empty() )
return;
const XMLCh* fmtCntModel = element->getFormattedContentModel();
if ( fmtCntModel != NULL ) // tbd: this does not yet pick up prefix:localname combinations
{
wxString structure = WrapXerces::toString ( fmtCntModel );
d->elementStructureMap[name] = structure;
}
const ContentSpecNode *spec = element->getContentSpec();
if ( spec != NULL )
{
getContent ( d->elementMap[name], spec, substitutions );
}
// fetch attributes
if ( !element->hasAttDefs() )
return;
XMLAttDefList& attIter = element->getAttDefList();
2014-04-24 14:14:29 +02:00
unsigned int i = 0;
for ( ; i < attIter.getAttDefCount() && !TestDestroy(); i++ )
{
wxString attribute, attributeValue;
XMLAttDef& attr = attIter.getAttDef ( i );
XMLAttDef::DefAttTypes ty = attr.getDefaultType();
if ( ty == XMLAttDef::Prohibited )
continue;
attribute = WrapXerces::toString ( attr.getFullName() );
if ( attribute.empty() )
2012-08-06 17:27:22 +02:00
continue;
// Value
attributeValue = WrapXerces::toString ( attr.getValue() );
d->attributeMap[name][attribute].insert( attributeValue );
if ( ty == XMLAttDef::Required || ty == XMLAttDef::Required_And_Fixed)
d->requiredAttributeMap[name].insert ( attribute );
2009-11-06 18:06:12 +01:00
}
}
void XmlPromptGenerator::buildSubstitutionMap (
SubstitutionMap &substitutions,
const SchemaGrammar &grammar )
{
substitutions.clear();
RefHash2KeysTableOfEnumerator<ElemVector> list ( grammar.getValidSubstitutionGroups() );
if ( !list.hasMoreElements() )
return;
2014-04-24 14:14:29 +02:00
while ( list.hasMoreElements() && !TestDestroy() )
{
const ElemVector &elmts = list.nextElement();
const QName *qnm;
const SchemaElementDecl *cur, *substitution;
substitution = elmts.elementAt ( 0 )->getSubstitutionGroupElem();
size_t index = elmts.size();
while ( index-- > 0 )
{
cur = elmts.elementAt ( index );
qnm = cur->getElementName();
wxString element = WrapXerces::toString ( qnm->getRawName() );
substitutions[substitution].insert ( element );
}
}
}
void XmlPromptGenerator::getContent (
std::set<wxString> &list,
const ContentSpecNode *spec,
SubstitutionMap &substitutions )
{
2014-04-24 14:14:29 +02:00
if ( TestDestroy() )
return;
//if ( spec == NULL) return;
const QName *qnm = spec->getElement();
if ( qnm )
{
const SchemaElementDecl *elem = (const SchemaElementDecl *)spec->getElementDecl();
SubstitutionMap::const_iterator itr = substitutions.find ( elem );
if ( itr == substitutions.end() && elem != NULL )
itr = substitutions.find ( elem->getSubstitutionGroupElem() );
if ( itr != substitutions.end() )
{
list.insert ( itr->second.begin(), itr->second.end() );
}
else
{
wxString element = WrapXerces::toString ( qnm->getRawName() );
if ( !element.IsEmpty() )
list.insert( element );
}
}
if ( spec->getFirst() != NULL)
getContent( list, spec->getFirst(), substitutions );
if ( spec->getSecond() != NULL)
getContent( list, spec->getSecond(), substitutions );
}
2014-04-24 14:14:29 +02:00
void *XmlPromptGenerator::Entry()
{
if ( TestDestroy() )
return NULL;
parse ( mBuffer );
wxCriticalSectionLocker locker ( xmlcopyeditorCriticalSection );
if ( !TestDestroy() )
{
wxNotifyEvent event ( myEVT_NOTIFY_PROMPT_GENERATED );
wxPostEvent ( mEventHandler, event );
}
return NULL;
}
void XmlPromptGenerator::PendingDelete ()
{
Cancel();
ThreadReaper::get().add ( this );
}