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));
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)
163 parser.onEndDocument();
165 END_SAFE_PARSER_BLOCK
168 #if !NCML_PARSER_USE_SAX2_NAMESPACES
170 static void ncmlStartElement(
void * userData,
171 const xmlChar * name,
172 const xmlChar ** attrs)
175 BEGIN_SAFE_PARSER_BLOCK(1)
177 string nameS =
XMLUtil::xmlCharToString(name);
179 toXMLAttributeMapNoNamespaces(map, attrs);
182 parser.onStartElement(nameS, map);
184 END_SAFE_PARSER_BLOCK
187 static
void ncmlEndElement(
void * userData,
188 const xmlChar * name)
190 BEGIN_SAFE_PARSER_BLOCK(1)
192 string nameS =
XMLUtil::xmlCharToString(name);
193 parser.onEndElement(nameS);
195 END_SAFE_PARSER_BLOCK
199 #if NCML_PARSER_USE_SAX2_NAMESPACES
201 void ncmlSax2StartElementNs(
void *userData,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
202 int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int ,
203 const xmlChar **attributes)
206 BEGIN_SAFE_PARSER_BLOCK(userData)
208 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlSax2StartElementNs() - localname:" << localname << endl);
211 toXMLAttributeMapWithNamespaces(attrMap, attributes, nb_attributes);
217 string localnameString = XMLUtil::xmlCharToString(localname);
218 string prefixString = XMLUtil::xmlCharToString(prefix);
219 string uriString = XMLUtil::xmlCharToString(URI);
221 parser.onStartElementWithNamespace(
228 END_SAFE_PARSER_BLOCK
232 void ncmlSax2EndElementNs(
void *userData,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI)
234 BEGIN_SAFE_PARSER_BLOCK(userData)
236 string localnameString = XMLUtil::xmlCharToString(localname);
237 string prefixString = XMLUtil::xmlCharToString(prefix);
238 string uriString = XMLUtil::xmlCharToString(URI);
239 parser.onEndElementWithNamespace(localnameString, prefixString, uriString);
241 END_SAFE_PARSER_BLOCK
245 static void ncmlCharacters(
void* userData,
const xmlChar* content,
int len)
247 BEGIN_SAFE_PARSER_BLOCK(userData)
252 string characters(
"");
253 characters.reserve(len);
254 const xmlChar* contentEnd = content+len;
255 while(content != contentEnd)
257 characters += (
const char)(*content++);
260 parser.onCharacters(characters);
262 END_SAFE_PARSER_BLOCK
265 static void ncmlWarning(
void* userData,
const char* msg, ...)
267 BEGIN_SAFE_PARSER_BLOCK(userData)
269 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlWarning() - msg:" << msg << endl);
274 unsigned int len =
sizeof(buffer);
275 vsnprintf(buffer, len, msg, args);
277 parser.onParseWarning(
string(buffer));
279 END_SAFE_PARSER_BLOCK
282 static void ncmlFatalError(
void* userData,
const char* msg, ...)
284 BEGIN_SAFE_PARSER_BLOCK(userData)
286 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlFatalError() - msg:" << msg << endl);
291 unsigned int len =
sizeof(buffer);
292 vsnprintf(buffer, len, msg, args);
294 parser.onParseError(
string(buffer));
296 END_SAFE_PARSER_BLOCK
303 _parser(parser), _handler(), _state(NOT_PARSING), _errorMsg(
""), _errorType(0), _errorFile(
""), _errorLine(-1)
307 SaxParserWrapper::~SaxParserWrapper()
310 _state = NOT_PARSING;
319 if (_state == PARSING) {
320 throw BESInternalError(
"Parse called again while already in parse.", __FILE__, __LINE__);
328 bool success = xmlSAXUserParseFile(&_handler,
this, ncmlFilename.c_str());
336 _state = NOT_PARSING;
354 _state = NOT_PARSING;
356 switch (_errorType) {
357 case BES_INTERNAL_ERROR:
360 case BES_INTERNAL_FATAL_ERROR:
363 case BES_SYNTAX_USER_ERROR:
366 case BES_FORBIDDEN_ERROR:
369 case BES_NOT_FOUND_ERROR:
381 return xmlSAX2GetLineNumber(_context);
390 static void setAllHandlerCBToNulls(xmlSAXHandler& h)
392 h.internalSubset = 0;
394 h.hasInternalSubset = 0;
395 h.hasExternalSubset = 0;
402 h.unparsedEntityDecl = 0;
403 h.setDocumentLocator = 0;
410 h.ignorableWhitespace = 0;
411 h.processingInstruction = 0;
416 h.getParameterEntity = 0;
418 h.externalSubset = 0;
423 h.startElementNs = 0;
428 void SaxParserWrapper::setupParser()
434 xmlSAXVersion(&_handler, 2);
438 setAllHandlerCBToNulls(_handler);
441 _handler.startDocument = ncmlStartDocument;
442 _handler.endDocument = ncmlEndDocument;
443 _handler.warning = ncmlWarning;
444 _handler.error = ncmlFatalError;
445 _handler.fatalError = ncmlFatalError;
446 _handler.characters = ncmlCharacters;
449 #if NCML_PARSER_USE_SAX2_NAMESPACES
450 _handler.startElement = 0;
451 _handler.endElement = 0;
452 _handler.startElementNs = ncmlSax2StartElementNs;
453 _handler.endElementNs = ncmlSax2EndElementNs;
455 _handler.startElement = ncmlStartElement;
456 _handler.endElement = ncmlEndElement;
457 _handler.startElementNs = 0;
458 _handler.endElementNs = 0;
463 void SaxParserWrapper::cleanupParser() throw ()
Abstract exception class for the BES with basic string message.
virtual int get_bes_error_type()
Return the return code for this error class.
virtual int get_line()
get the line number where the exception was thrown
virtual std::string get_file()
get the file name where the exception was thrown
virtual std::string get_message()
get the error message for this exception
error thrown if the BES is not allowed to access the resource requested
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
error thrown if the resource requested cannot be found
error thrown if there is a user syntax error in the request or any other user error
bool parse(const std::string &ncmlFilename)
Do a SAX parse of the ncmlFilename and pass the calls to wrapper parser.
bool isExceptionState() const
void deferException(BESError &theErr)
The remaining calls are for the internals of the parser, but need to be public.
int getCurrentParseLine() const
Interface class for the wrapper between libxml C SAX parser and our NCMLParser.
void addAttribute(const XMLAttribute &attribute)
void fromSAX2Namespaces(const xmlChar **pNamespaces, int numNamespaces)
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...
void fromSAX2NamespaceAttributes(const xmlChar **chunkOfFivePointers)