32 #include "SaxParserWrapper.h"
36 #include <libxml/parser.h>
37 #include <libxml/xmlstring.h>
43 #include "BESInternalError.h"
44 #include "BESInternalFatalError.h"
45 #include "BESSyntaxUserError.h"
46 #include "BESForbiddenError.h"
47 #include "BESNotFoundError.h"
48 #include "NCMLDebug.h"
49 #include "SaxParser.h"
50 #include "XMLHelpers.h"
56 #define NCML_PARSER_USE_SAX2_NAMESPACES 1
64 #if NCML_PARSER_USE_SAX2_NAMESPACES
65 static const int SAX2_NAMESPACE_ATTRIBUTE_ARRAY_STRIDE = 5;
66 static int toXMLAttributeMapWithNamespaces(
XMLAttributeMap& attrMap,
const xmlChar** attributes,
int num_attributes)
69 for (
int i = 0; i < num_attributes; ++i) {
72 attributes += SAX2_NAMESPACE_ATTRIBUTE_ARRAY_STRIDE;
75 return num_attributes;
79 static int toXMLAttributeMapNoNamespaces(
XMLAttributeMap& attrMap,
const xmlChar** attrs)
83 while (attrs && *attrs != NULL)
86 attr.localname = XMLUtil::xmlCharToString(*attrs);
87 attr.value = XMLUtil::xmlCharToString(*(attrs+1));
114 #define BEGIN_SAFE_PARSER_BLOCK(argName) { \
115 SaxParserWrapper* _spw_ = static_cast<SaxParserWrapper*>(argName); \
116 if (_spw_->isExceptionState()) \
124 SaxParser& parser = _spw_->getParser(); \
125 parser.setParseLineNumber(_spw_->getCurrentParseLine());
128 #define END_SAFE_PARSER_BLOCK } \
129 catch (BESError& theErr) \
131 BESDEBUG("ncml", "Caught BESError&, deferring..." << endl); \
132 _spw_->deferException(theErr); \
134 catch (std::exception& ex) \
136 BESDEBUG("ncml", "Caught std::exception&, wrapping and deferring..." << endl); \
137 BESInternalError _badness_("Wrapped std::exception.what()=" + string(ex.what()), __FILE__, __LINE__);\
138 _spw_->deferException(_badness_); \
142 BESDEBUG("ncml", "Caught unknown (...) exception: deferring default error." << endl); \
143 BESInternalError _badness_("SaxParserWrapper:: Unknown Exception Type: ", __FILE__, __LINE__); \
144 _spw_->deferException(_badness_); \
152 static void ncmlStartDocument(
void* userData)
154 BEGIN_SAFE_PARSER_BLOCK(userData)
156 parser.onStartDocument();
158 END_SAFE_PARSER_BLOCK
161 static void ncmlEndDocument(
void* userData)
163 BEGIN_SAFE_PARSER_BLOCK(userData)
165 parser.onEndDocument();
167 END_SAFE_PARSER_BLOCK
170 #if !NCML_PARSER_USE_SAX2_NAMESPACES
172 static void ncmlStartElement(
void * userData,
173 const xmlChar * name,
174 const xmlChar ** attrs)
177 BEGIN_SAFE_PARSER_BLOCK(1)
179 string nameS =
XMLUtil::xmlCharToString(name);
181 toXMLAttributeMapNoNamespaces(map, attrs);
184 parser.onStartElement(nameS, map);
186 END_SAFE_PARSER_BLOCK
189 static
void ncmlEndElement(
void * userData,
190 const xmlChar * name)
192 BEGIN_SAFE_PARSER_BLOCK(1)
194 string nameS =
XMLUtil::xmlCharToString(name);
195 parser.onEndElement(nameS);
197 END_SAFE_PARSER_BLOCK
201 #if NCML_PARSER_USE_SAX2_NAMESPACES
203 void ncmlSax2StartElementNs(
void *userData,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
204 int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int ,
205 const xmlChar **attributes)
208 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
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));
281 END_SAFE_PARSER_BLOCK
284 static void ncmlFatalError(
void* userData,
const char* msg, ...)
286 BEGIN_SAFE_PARSER_BLOCK(userData)
288 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlFatalError() - msg:" << msg << endl);
293 unsigned int len =
sizeof(buffer);
294 vsnprintf(buffer, len, msg, args);
296 parser.onParseError(
string(buffer));
298 END_SAFE_PARSER_BLOCK
305 _parser(parser), _handler(), _state(NOT_PARSING), _errorMsg(
""), _errorType(0), _errorFile(
""), _errorLine(-1)
309 SaxParserWrapper::~SaxParserWrapper()
312 _state = NOT_PARSING;
321 if (_state == PARSING) {
322 throw BESInternalError(
"Parse called again while already in parse.", __FILE__, __LINE__);
330 bool success = xmlSAXUserParseFile(&_handler,
this, ncmlFilename.c_str());
338 _state = NOT_PARSING;
356 _state = NOT_PARSING;
358 switch (_errorType) {
359 case BES_INTERNAL_ERROR:
362 case BES_INTERNAL_FATAL_ERROR:
365 case BES_SYNTAX_USER_ERROR:
368 case BES_FORBIDDEN_ERROR:
371 case BES_NOT_FOUND_ERROR:
383 return xmlSAX2GetLineNumber(_context);
392 static void setAllHandlerCBToNulls(xmlSAXHandler& h)
394 h.internalSubset = 0;
396 h.hasInternalSubset = 0;
397 h.hasExternalSubset = 0;
404 h.unparsedEntityDecl = 0;
405 h.setDocumentLocator = 0;
412 h.ignorableWhitespace = 0;
413 h.processingInstruction = 0;
418 h.getParameterEntity = 0;
420 h.externalSubset = 0;
425 h.startElementNs = 0;
430 void SaxParserWrapper::setupParser()
436 xmlSAXVersion(&_handler, 2);
440 setAllHandlerCBToNulls(_handler);
443 _handler.startDocument = ncmlStartDocument;
444 _handler.endDocument = ncmlEndDocument;
445 _handler.warning = ncmlWarning;
446 _handler.error = ncmlFatalError;
447 _handler.fatalError = ncmlFatalError;
448 _handler.characters = ncmlCharacters;
451 #if NCML_PARSER_USE_SAX2_NAMESPACES
452 _handler.startElement = 0;
453 _handler.endElement = 0;
454 _handler.startElementNs = ncmlSax2StartElementNs;
455 _handler.endElementNs = ncmlSax2EndElementNs;
457 _handler.startElement = ncmlStartElement;
458 _handler.endElement = ncmlEndElement;
459 _handler.startElementNs = 0;
460 _handler.endElementNs = 0;
465 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)