30 #include "SaxParserWrapper.h"
34 #include <libxml/parser.h>
35 #include <libxml/xmlstring.h>
41 #include "BESInternalError.h"
42 #include "BESInternalFatalError.h"
43 #include "BESSyntaxUserError.h"
44 #include "BESForbiddenError.h"
45 #include "BESNotFoundError.h"
46 #include "NCMLDebug.h"
47 #include "SaxParser.h"
48 #include "XMLHelpers.h"
54 #define NCML_PARSER_USE_SAX2_NAMESPACES 1
62 #if NCML_PARSER_USE_SAX2_NAMESPACES
63 static const int SAX2_NAMESPACE_ATTRIBUTE_ARRAY_STRIDE = 5;
64 static int toXMLAttributeMapWithNamespaces(
XMLAttributeMap& attrMap,
const xmlChar** attributes,
int num_attributes)
67 for (
int i = 0; i < num_attributes; ++i) {
70 attributes += SAX2_NAMESPACE_ATTRIBUTE_ARRAY_STRIDE;
73 return num_attributes;
77 static int toXMLAttributeMapNoNamespaces(
XMLAttributeMap& attrMap,
const xmlChar** attrs)
81 while (attrs && *attrs != NULL)
84 attr.localname = XMLUtil::xmlCharToString(*attrs);
85 attr.value = XMLUtil::xmlCharToString(*(attrs+1));
92 #endif // NCML_PARSER_USE_SAX2_NAMESPACES
112 #define BEGIN_SAFE_PARSER_BLOCK(argName) { \
113 SaxParserWrapper* _spw_ = static_cast<SaxParserWrapper*>(argName); \
114 if (_spw_->isExceptionState()) \
122 SaxParser& parser = _spw_->getParser(); \
123 parser.setParseLineNumber(_spw_->getCurrentParseLine());
126 #define END_SAFE_PARSER_BLOCK } \
127 catch (BESError& theErr) \
129 BESDEBUG("ncml", "Caught BESError&, deferring..." << endl); \
130 _spw_->deferException(theErr); \
132 catch (std::exception& ex) \
134 BESDEBUG("ncml", "Caught std::exception&, wrapping and deferring..." << endl); \
135 BESInternalError _badness_("Wrapped std::exception.what()=" + string(ex.what()), __FILE__, __LINE__);\
136 _spw_->deferException(_badness_); \
140 BESDEBUG("ncml", "Caught unknown (...) exception: deferring default error." << endl); \
141 BESInternalError _badness_("SaxParserWrapper:: Unknown Exception Type: ", __FILE__, __LINE__); \
142 _spw_->deferException(_badness_); \
150 static void ncmlStartDocument(
void* userData)
152 BEGIN_SAFE_PARSER_BLOCK(userData)
154 parser.onStartDocument();
156 END_SAFE_PARSER_BLOCK;
159 static void ncmlEndDocument(
void* userData)
161 BEGIN_SAFE_PARSER_BLOCK(userData)
164 parser.onEndDocument();
168 END_SAFE_PARSER_BLOCK;
171 #if !NCML_PARSER_USE_SAX2_NAMESPACES
173 static void ncmlStartElement(
void * userData,
174 const xmlChar * name,
175 const xmlChar ** attrs)
178 BEGIN_SAFE_PARSER_BLOCK(userData);
180 string nameS = XMLUtil::xmlCharToString(name);
182 toXMLAttributeMapNoNamespaces(map, attrs);
185 parser.onStartElement(nameS, map);
187 END_SAFE_PARSER_BLOCK;
190 static void ncmlEndElement(
void * userData,
191 const xmlChar * name)
193 BEGIN_SAFE_PARSER_BLOCK(userData);
195 string nameS = XMLUtil::xmlCharToString(name);
196 parser.onEndElement(nameS);
198 END_SAFE_PARSER_BLOCK;
200 #endif // !NCML_PARSER_USE_SAX2_NAMESPACES
202 #if NCML_PARSER_USE_SAX2_NAMESPACES
204 void ncmlSax2StartElementNs(
void *userData,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
205 int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int ,
206 const xmlChar **attributes)
209 BEGIN_SAFE_PARSER_BLOCK(userData);
210 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlSax2StartElementNs() - localname:" << localname << endl);
213 toXMLAttributeMapWithNamespaces(attrMap, attributes, nb_attributes);
219 string localnameString = XMLUtil::xmlCharToString(localname);
220 string prefixString = XMLUtil::xmlCharToString(prefix);
221 string uriString = XMLUtil::xmlCharToString(URI);
223 parser.onStartElementWithNamespace(
230 END_SAFE_PARSER_BLOCK;
234 void ncmlSax2EndElementNs(
void *userData,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI)
236 BEGIN_SAFE_PARSER_BLOCK(userData);
238 string localnameString = XMLUtil::xmlCharToString(localname);
239 string prefixString = XMLUtil::xmlCharToString(prefix);
240 string uriString = XMLUtil::xmlCharToString(URI);
241 parser.onEndElementWithNamespace(localnameString, prefixString, uriString);
243 END_SAFE_PARSER_BLOCK;
245 #endif // NCML_PARSER_USE_SAX2_NAMESPACES
247 static void ncmlCharacters(
void* userData,
const xmlChar* content,
int len)
249 BEGIN_SAFE_PARSER_BLOCK(userData);
254 string characters(
"");
255 characters.reserve(len);
256 const xmlChar* contentEnd = content+len;
257 while(content != contentEnd)
259 characters += (
const char)(*content++);
262 parser.onCharacters(characters);
264 END_SAFE_PARSER_BLOCK;
267 static void ncmlWarning(
void* userData,
const char* msg, ...)
269 BEGIN_SAFE_PARSER_BLOCK(userData);
271 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlWarning() - msg:" << msg << endl);
276 unsigned int len =
sizeof(buffer);
277 vsnprintf(buffer, len, msg, args);
279 parser.onParseWarning(
string(buffer));
280 END_SAFE_PARSER_BLOCK;
283 static void ncmlFatalError(
void* userData,
const char* msg, ...)
285 BEGIN_SAFE_PARSER_BLOCK(userData);
287 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlFatalError() - msg:" << msg << endl);
292 unsigned int len =
sizeof(buffer);
293 vsnprintf(buffer, len, msg, args);
295 parser.onParseError(
string(buffer));
297 END_SAFE_PARSER_BLOCK;
304 _parser(parser), _handler(),
305 _state(NOT_PARSING), _errorMsg(
""), _errorType(0), _errorFile(
""), _errorLine(-1)
309 SaxParserWrapper::~SaxParserWrapper()
312 _state = NOT_PARSING;
325 if (_state == PARSING) {
326 throw BESInternalError(
"Parse called again while already in parse.", __FILE__, __LINE__);
333 setupParser(ncmlFilename);
335 success = xmlSAXUserParseFile(&_handler,
this, ncmlFilename.c_str());
345 xmlParseDocument(_context);
347 success = (_context->errNo == 0);
358 _state = NOT_PARSING;
376 _state = NOT_PARSING;
378 switch (_errorType) {
379 case BES_INTERNAL_ERROR:
383 case BES_INTERNAL_FATAL_ERROR:
387 case BES_SYNTAX_USER_ERROR:
391 case BES_FORBIDDEN_ERROR:
395 case BES_NOT_FOUND_ERROR:
409 return xmlSAX2GetLineNumber(_context);
418 static void setAllHandlerCBToNulls(xmlSAXHandler& h)
420 h.internalSubset = 0;
422 h.hasInternalSubset = 0;
423 h.hasExternalSubset = 0;
430 h.unparsedEntityDecl = 0;
431 h.setDocumentLocator = 0;
438 h.ignorableWhitespace = 0;
439 h.processingInstruction = 0;
444 h.getParameterEntity = 0;
446 h.externalSubset = 0;
451 h.startElementNs = 0;
456 void SaxParserWrapper::setupParser(
const string& filename)
462 xmlSAXVersion(&_handler, 2);
466 setAllHandlerCBToNulls(_handler);
469 _handler.startDocument = ncmlStartDocument;
470 _handler.endDocument = ncmlEndDocument;
471 _handler.warning = ncmlWarning;
472 _handler.error = ncmlFatalError;
473 _handler.fatalError = ncmlFatalError;
474 _handler.characters = ncmlCharacters;
477 #if NCML_PARSER_USE_SAX2_NAMESPACES
478 _handler.startElement = 0;
479 _handler.endElement = 0;
480 _handler.startElementNs = ncmlSax2StartElementNs;
481 _handler.endElementNs = ncmlSax2EndElementNs;
483 _handler.startElement = ncmlStartElement;
484 _handler.endElement = ncmlEndElement;
485 _handler.startElementNs = 0;
486 _handler.endElementNs = 0;
487 #endif // NCML_PARSER_USE_SAX2_NAMESPACES
495 _context = xmlCreateFileParserCtxt(filename.c_str());
497 THROW_NCML_PARSE_ERROR(-1,
"Cannot parse: Unable to create a libxml parse context for " + filename);
499 _context->sax = &_handler;
500 _context->userData =
this;
501 _context->validate =
false;
507 void SaxParserWrapper::cleanupParser() throw ()
513 _context->sax = NULL;
516 xmlFreeParserCtxt(_context);