34 #include <libxml/parser.h>
35 #include <libxml/xmlstring.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)
71 attributes += SAX2_NAMESPACE_ATTRIBUTE_ARRAY_STRIDE;
74 return num_attributes;
78 static int toXMLAttributeMapNoNamespaces(
XMLAttributeMap& attrMap,
const xmlChar** attrs)
82 while (attrs && *attrs !=
NULL)
85 attr.
localname = XMLUtil::xmlCharToString(*attrs);
86 attr.
value = XMLUtil::xmlCharToString(*(attrs+1));
93 #endif // NCML_PARSER_USE_SAX2_NAMESPACES
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)
156 parser.onStartDocument();
161 static void ncmlEndDocument(
void* userData)
165 parser.onEndDocument();
170 #if !NCML_PARSER_USE_SAX2_NAMESPACES
172 static void ncmlStartElement(
void * userData,
173 const xmlChar * name,
174 const xmlChar ** attrs)
179 string nameS = XMLUtil::xmlCharToString(name);
181 toXMLAttributeMapNoNamespaces(map, attrs);
184 parser.onStartElement(nameS, map);
189 static void ncmlEndElement(
void * userData,
190 const xmlChar * name)
194 string nameS = XMLUtil::xmlCharToString(name);
195 parser.onEndElement(nameS);
199 #endif // !NCML_PARSER_USE_SAX2_NAMESPACES
201 #if NCML_PARSER_USE_SAX2_NAMESPACES
204 ncmlSax2StartElementNs(
void *userData,
205 const xmlChar *localname,
206 const xmlChar *prefix,
209 const xmlChar **namespaces,
212 const xmlChar **attributes)
218 toXMLAttributeMapWithNamespaces(attrMap, attributes, nb_attributes);
224 string localnameString = XMLUtil::xmlCharToString(localname);
225 string prefixString = XMLUtil::xmlCharToString(prefix);
226 string uriString = XMLUtil::xmlCharToString(URI);
228 parser.onStartElementWithNamespace(
240 ncmlSax2EndElementNs(
void *userData,
241 const xmlChar *localname,
242 const xmlChar *prefix,
247 string localnameString = XMLUtil::xmlCharToString(localname);
248 string prefixString = XMLUtil::xmlCharToString(prefix);
249 string uriString = XMLUtil::xmlCharToString(URI);
250 parser.onEndElementWithNamespace(localnameString, prefixString, uriString);
254 #endif // NCML_PARSER_USE_SAX2_NAMESPACES
256 static void ncmlCharacters(
void* userData,
const xmlChar* content,
int len)
260 BESDEBUG(
"ncml",
"ncmlCharacters: len:" << len <<
", content: " << content << endl);
265 string characters(
"");
266 characters.reserve(len);
267 const xmlChar* contentEnd = content+len;
268 while(content != contentEnd)
270 characters += (
const char)(*content++);
273 parser.onCharacters(characters);
278 static void ncmlWarning(
void* userData,
const char* msg, ...)
284 unsigned int len =
sizeof(buffer);
285 vsnprintf(buffer, len, msg, args);
287 parser.onParseWarning(
string(buffer));
291 static void ncmlFatalError(
void* userData,
const char* msg, ...)
297 unsigned int len =
sizeof(buffer);
298 vsnprintf(buffer, len, msg, args);
300 parser.onParseError(
string(buffer));
311 , _state(NOT_PARSING)
322 _state = NOT_PARSING;
332 if (_state == PARSING)
334 throw BESInternalError(
"Parse called again while already in parse.", __FILE__, __LINE__);
340 setupParser(ncmlFilename);
349 xmlParseDocument(_context);
351 success = (_context->errNo == 0);
362 _state = NOT_PARSING;
382 _state = NOT_PARSING;
417 return xmlSAX2GetLineNumber(_context);
425 static void setAllHandlerCBToNulls(xmlSAXHandler& h)
427 h.internalSubset = 0;
429 h.hasInternalSubset = 0;
430 h.hasExternalSubset = 0;
437 h.unparsedEntityDecl = 0;
438 h.setDocumentLocator = 0;
445 h.ignorableWhitespace = 0;
446 h.processingInstruction = 0;
451 h.getParameterEntity = 0;
453 h.externalSubset = 0;
459 h.startElementNs = 0;
465 SaxParserWrapper::setupParser(
const string& filename)
471 xmlSAXVersion(&_handler, 2);
475 setAllHandlerCBToNulls(_handler);
478 _handler.startDocument = ncmlStartDocument;
479 _handler.endDocument = ncmlEndDocument;
480 _handler.warning = ncmlWarning;
481 _handler.error = ncmlFatalError;
482 _handler.fatalError = ncmlFatalError;
483 _handler.characters = ncmlCharacters;
486 #if NCML_PARSER_USE_SAX2_NAMESPACES
487 _handler.startElement = 0;
488 _handler.endElement = 0;
489 _handler.startElementNs = ncmlSax2StartElementNs;
490 _handler.endElementNs = ncmlSax2EndElementNs;
492 _handler.startElement = ncmlStartElement;
493 _handler.endElement = ncmlEndElement;
494 _handler.startElementNs = 0;
495 _handler.endElementNs = 0;
496 #endif // NCML_PARSER_USE_SAX2_NAMESPACES
501 _context = xmlCreateFileParserCtxt(filename.c_str());
505 "Cannot parse: Unable to create a libxml parse context for " + filename);
507 _context->sax = &_handler;
508 _context->userData =
this;
509 _context->validate =
false;
513 SaxParserWrapper::cleanupParser() throw ()
518 _context->sax =
NULL;
521 xmlFreeParserCtxt(_context);
#define BES_SYNTAX_USER_ERROR
void rethrowException()
If there's a deferred exception, this will throw the right subclass type from the preserved state at ...
error thrown if the resource requested cannot be found
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
#define BES_INTERNAL_ERROR
bool isExceptionState() const
Used by the callbacks to know whether we have a deferred exception.
void deferException(BESError &theErr)
The remaining calls are for the internals of the parser, but need to be public.
An abstract superclass for NCMLArray that handles the non-parameterized functionality and allows u...
#define BES_FORBIDDEN_ERROR
#define BEGIN_SAFE_PARSER_BLOCK(argName)
bool parse(const string &ncmlFilename)
Do a SAX parse of the ncmlFilename and pass the calls to wrapper parser.
error thrown if there is a user syntax error in the request or any other user error ...
virtual int get_error_type()
Return the return code for this error class.
virtual string get_file()
get the file name where the exception was thrown
virtual string get_message()
get the error message for this exception
void fromSAX2Namespaces(const xmlChar **pNamespaces, int numNamespaces)
Read them all in from the xmlChar array.
Abstract exception class for the BES with basic string message.
int getCurrentParseLine() const
Return the current line of the parse we're on, assuming we're not in an exception state and that we a...
#define THROW_NCML_PARSE_ERROR(parseLine, msg)
virtual ~SaxParserWrapper()
void addAttribute(const XMLAttribute &attribute)
TODO how do we tell if this exists? Does it replace? Do we care?
#define BES_INTERNAL_FATAL_ERROR
error thrown if the BES is not allowed to access the resource requested
#define BES_NOT_FOUND_ERROR
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Interface class for the wrapper between libxml C SAX parser and our NCMLParser.
void fromSAX2NamespaceAttributes(const xmlChar **chunkOfFivePointers)
Fill in the fields from the SAX2 namespace attributes array.
virtual int get_line()
get the line number where the exception was thrown
#define END_SAFE_PARSER_BLOCK