tags:

views:

48

answers:

3

Hi, I'm using the Xerces C++ DOM parser to read some XML files in a Visual C++ project. I have a class with a parse() method that is supposed to read and validate my XML source file. This is what the method looks like:

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/dom/DOM.hpp>           
#include <xercesc/parsers/XercesDOMParser.hpp>  
#include <xercesc/framework/LocalFileInputSource.hpp>

using namespace std;
XERCES_CPP_NAMESPACE_USE

unsigned long RulesParser::parse( const wstring &xmlFile )
{
  if( parserInitialized_ == false ) {
    try {
      XMLPlatformUtils::Initialize();   /* initialize xerces */
    } catch( XMLException const &e ) {
      return Status::PARSER_INIT_FAIL;
    }
  }
  parserInitialized_  = true;           /* indicate xerces has been successfully initialized */

  if( pDOMParser_ != NULL ) {
    delete pDOMParser_;
  }
  pDOMParser_ = new XercesDOMParser;    /* create a DOM parser instance */
  /* set xerces options */
  pDOMParser_->setDoNamespaces( true ); /* enable namespace processing */
  pDOMParser_->setDoSchema( true );     /* enable schema processing */
  pDOMParser_->setValidationScheme( XercesDOMParser::Val_Always );  /* parser always validates */
  pDOMParser_->setValidationSchemaFullChecking( true ); /* enable full schema checking */

  auto_ptr< LocalFileInputSource > srcFile; /* XML source file loader */

  try {
    srcFile.reset( new LocalFileInputSource( xmlFile.c_str() ) );

  } catch( const XMLException &e ) {
    return Status::XML_SOURCE_LOAD_ERROR;
  }

  /* parse the file */
  try {
    pDOMParser_->parse( *srcFile );

  } catch( const XMLException &e ) {    
    return Status::XML_SOURCE_PARSE_ERROR;

  } catch( const DOMException &e ) {
    return Status::XML_SOURCE_PARSE_DOM_ERROR;
  }

  return Status::OK;
}

The documentation for LocalFileInputSource says the constructor will throw an XMLException if the path doesn't resolve to a file. However, I can call this method with any arbitrary string and it executes to the end without any exceptions being raised. What am I doing wrong?

Also, the documentation for XercesDOMParser::parse() says a SAXException is one of the types of exceptions that it can throw. I find this confusing because from what I understand DOM and SAX parsers are 2 different animals, so why would the DOM parser throw a SAX exception?

Thanks for your responses, Ashish.

+1  A: 

See ErrorHandler documentation.

You must declare and define a class that inherits from ErrorHandler and implements its virtual methods (or you can extend the HandlerBase class).

Then you must call setErrorHandler on your parser instance passing an instance of your error handler, i.e. pDOMParser_->setErrorHandler(your_handler_instance).

Example usage from Xerces-C++ trunk samples: rows 231-233 of SAXPrint.cpp.

Update: example of custom error handler below.

#include <iostream>
#include <xercesc/sax/HandlerBase.hpp>
XERCES_CPP_NAMESPACE_USE

class CustomErrorHandler : public HandlerBase
{

    public:

        CustomErrorHandler() {}

        void error(const SAXParseException& e)
        {
            handler(e);
        }

        void fatalError(const SAXParseException& e)
        {
            handler(e);
        }

        void warning(const SAXParseException& e)
        {
            handler(e);
        }

    private:

        void handler(const SAXParseException& e)
        {
            char* message = XMLString::transcode(e.getMessage());

            cerr << "line " << e.getLineNumber()
                 << ", column " << e.getColumnNumber()
                 << " -> " << message << "\n\n";

            XMLString::release(&message);
        }
};
Vanni Totaro
I'll give this a try. Funny thing is I haven't come across any Xerces tutorials so far that say this needs to be done. All of them happily put `try ... catch` around `XercesDOMParser::parse()` to catch errors.
Praetorian
@`praetorian20`: I've just edited my post with a custom error class implementation example.
Vanni Totaro
@Vanni, that worked! Thank you so much for the example and posting the link to the `SAXPrint` example.
Praetorian
@`praetorian20`: you're welcome! :)
Vanni Totaro
A: 

I don't think that the documentation says what you think it does, it says it will; throw:

XMLException If the path is relative and doesn't properly resolve to a file.

Your task, should you choose to accept it, is to find out what "relative" means. I'm afraid I I haven't used Xerces for years (though it is quite competent) - I prefer to use small, simple SAX parsers to build my own models rather than use a DOM, and can't remember how the filename stuff works.

And I think that the reason that you might get SAX exceptions is that Xerces uses SAX to build its DOM.

anon
A bit of fun with answer snap?
Greg Domjan
As I replied to Greg's comment, I've tried relative and absolute paths. In case of a relative path, Xerces is resolving it to an absolute path correctly (from looking at the `srcFile` variables contents in the watch window), but of course, it doesn't make any difference whether the file specified in the path exists or not.
Praetorian
A: 

The 2.8 Doc (you have linked) says,

XMLException If the path is relative and doesn't properly resolve to a file

are you actually using a relative path? maybe this used to be the case for some platform specific cases, but I can't see where this is raised in Xercese 2.7 (code I happen to have).

Looking at LocalFileFormatTarget it can throw an exception for 'CouldNotOpenFile', but it isn't documented as raising an exception.

What version of xerces are you using?

Opening the file for reading/parsing looks like it might raise an exception for the missing file of type 'CouldNotReadFromFile'. But that could be caught up with the error handling as Vanni is talking about.

Greg Domjan
I've tried both relative and absolute, neither of them throw an error.
Praetorian