/* * Copyright (C) 2004 SIPfoundry Inc. * Licensed by SIPfoundry under the LGPL license. * * Copyright (C) 2004 Pingtel Corp. * Licensed to SIPfoundry under a Contributor Agreement. * * Derived from: xerces-c sample application DOMCount, which is * Copyright 1999-2002,2004 The Apache Software Foundation. */ // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include #include "utl/UtlString.h" #include "sipxcommserverlib-buildstamp.h" #if defined(XERCES_NEW_IOSTREAMS) #include #else #include #endif #include #include XERCES_CPP_NAMESPACE_USE // --------------------------------------------------------------------------- // Simple error handler deriviative to install on parser // --------------------------------------------------------------------------- class XSDValidErrorHandler : public DOMErrorHandler { public: // ----------------------------------------------------------------------- // Constructors and Destructor // ----------------------------------------------------------------------- XSDValidErrorHandler(); ~XSDValidErrorHandler(); // ----------------------------------------------------------------------- // Getter methods // ----------------------------------------------------------------------- bool getSawErrors() const; // ----------------------------------------------------------------------- // Implementation of the DOM ErrorHandler interface // ----------------------------------------------------------------------- bool handleError(const DOMError& domError); void resetErrors(); private : // ----------------------------------------------------------------------- // Unimplemented constructors and operators // ----------------------------------------------------------------------- XSDValidErrorHandler(const XSDValidErrorHandler&); void operator=(const XSDValidErrorHandler&); // ----------------------------------------------------------------------- // Private data members // // fSawErrors // This is set if we get any errors, and is queryable via a getter // method. Its used by the main code to suppress output if there are // errors. // ----------------------------------------------------------------------- bool fSawErrors; }; // --------------------------------------------------------------------------- // This is a simple class that lets us do easy (though not terribly efficient) // trancoding of XMLCh data to local code page for display. // --------------------------------------------------------------------------- class StrX { public : // ----------------------------------------------------------------------- // Constructors and Destructor // ----------------------------------------------------------------------- StrX(const XMLCh* const toTranscode) { // Call the private transcoding method fLocalForm = XMLString::transcode(toTranscode); } ~StrX() { XMLString::release(&fLocalForm); } // ----------------------------------------------------------------------- // Getter methods // ----------------------------------------------------------------------- const char* localForm() const { return fLocalForm; } private : // ----------------------------------------------------------------------- // Private data members // // fLocalForm // This is the local code page form of the string. // ----------------------------------------------------------------------- char* fLocalForm; }; inline XERCES_STD_QUALIFIER ostream& operator<<(XERCES_STD_QUALIFIER ostream& target, const StrX& toDump) { target << toDump.localForm(); return target; } inline bool XSDValidErrorHandler::getSawErrors() const { return fSawErrors; } #if defined(XERCES_NEW_IOSTREAMS) #include #else #include #endif // --------------------------------------------------------------------------- // This is a simple program which invokes the DOMParser to build a DOM // tree for the specified input file. It then walks the tree and counts // the number of elements. The element count is then printed. // --------------------------------------------------------------------------- static void usage() { XERCES_STD_QUALIFIER cout << "\nUsage:\n" " xsdvalid [] " # ifdef LISTMODE "| -l " # endif "\n" "\n" "Validates an XML instance document against its schema as determined\n" "by examining the attributes in the document.\n" "\n" "Options:\n" " --version prints the version number\n" " -s|--schema \n" " Specifies a namespace and the location of a local copy of the \n" " schema definition file for that namespace.\n" " (may be repeated for multiple namespaces)\n" # ifdef LISTMODE " -l Indicate the input file is a List File that has a list of xml files.\n" " Default to off (Input file is an XML file).\n" # endif " -? Show this help.\n" "\n" " Returns zero if the file is valid, non-zero if not.\n" "\n" << XERCES_STD_QUALIFIER endl; } // --------------------------------------------------------------------------- // // main // // --------------------------------------------------------------------------- int main(int argC, char* argV[]) { // Check command line and extract arguments. if (argC < 2) { usage(); return 1; } const char* xmlFile = 0; AbstractDOMParser::ValSchemes valScheme = AbstractDOMParser::Val_Always; bool doNamespaces = true; bool doSchema = true; bool schemaFullChecking = true; bool doList = false; bool errorOccurred = false; char localeStr[64]; UtlString schemaLocationPairs; UtlString defaultSchema; memset(localeStr, 0, sizeof localeStr); int argInd; for (argInd = 1; argInd < argC; argInd++) { // Break out on first parm not starting with a dash if (argV[argInd][0] != '-') break; // Watch for special case help request if (!strcmp(argV[argInd], "-?")) { usage(); return 2; } if (!strcmp(argV[argInd], "--version")) { XERCES_STD_QUALIFIER cerr << "xsdvalid version " << SipXcommserverlibVersion << " build " << SipXcommserverlibBuildStamp << "\n" << XERCES_STD_QUALIFIER endl; return 0; } else if (!strcmp(argV[argInd], "-l") || !strcmp(argV[argInd], "-L")) { doList = true; } else if ( !strncmp(argV[argInd], "-s", 2) || !strncmp(argV[argInd], "--schema", 9) ) { if (argInd+2 < argC) { if (!schemaLocationPairs.isNull()) { schemaLocationPairs.append(" "); } schemaLocationPairs.append(argV[++argInd]); schemaLocationPairs.append(" "); schemaLocationPairs.append(argV[++argInd]); } else { XERCES_STD_QUALIFIER cerr << "Option '" << argV[argInd] << "' must be followed by \n" << XERCES_STD_QUALIFIER endl; return 2; } } else { XERCES_STD_QUALIFIER cerr << "Unknown option '" << argV[argInd] << "', ignoring it\n" << XERCES_STD_QUALIFIER endl; } } // // There should be only one and only one parameter left, and that // should be the file name. // if (argInd != argC - 1) { usage(); return 1; } // Initialize the XML4C system try { if (strlen(localeStr)) { XMLPlatformUtils::Initialize(localeStr); } else { XMLPlatformUtils::Initialize(); } } catch (const XMLException& toCatch) { XERCES_STD_QUALIFIER cerr << "Error during initialization! :\n" << StrX(toCatch.getMessage()) << XERCES_STD_QUALIFIER endl; return 1; } catch (...) { XERCES_STD_QUALIFIER cerr << "Unexpected error during initialization!\n"; return 1; } // Instantiate the DOM parser. static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull }; DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(gLS); DOMBuilder *parser = ((DOMImplementationLS*)impl)->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0); parser->setFeature(XMLUni::fgDOMNamespaces, doNamespaces); parser->setFeature(XMLUni::fgXercesSchema, doSchema); parser->setFeature(XMLUni::fgXercesSchemaFullChecking, schemaFullChecking); if (valScheme == AbstractDOMParser::Val_Auto) { parser->setFeature(XMLUni::fgDOMValidateIfSchema, true); } else if (valScheme == AbstractDOMParser::Val_Never) { parser->setFeature(XMLUni::fgDOMValidation, false); } else if (valScheme == AbstractDOMParser::Val_Always) { parser->setFeature(XMLUni::fgDOMValidation, true); } if (!schemaLocationPairs.isNull()) { XMLCh* propertyValue = XMLString::transcode(schemaLocationPairs.data()); parser->setProperty(XMLUni::fgXercesSchemaExternalSchemaLocation, propertyValue ); } // enable datatype normalization - default is off parser->setFeature(XMLUni::fgDOMDatatypeNormalization, true); // And create our error handler and install it XSDValidErrorHandler errorHandler; parser->setErrorHandler(&errorHandler); // // Get the starting time and kick off the parse of the indicated // file. Catch any exceptions that might propogate out of it. // unsigned long duration; bool more = true; XERCES_STD_QUALIFIER ifstream fin; // the input is a list file if (doList) fin.open(argV[argInd]); if (fin.fail()) { XERCES_STD_QUALIFIER cerr <<"Cannot open the list file: " << argV[argInd] << XERCES_STD_QUALIFIER endl; return 2; } while (more) { char fURI[1000]; //initialize the array to zeros memset(fURI,0,sizeof(fURI)); if (doList) { if (! fin.eof() ) { fin.getline (fURI, sizeof(fURI)); if (!*fURI) continue; else { xmlFile = fURI; XERCES_STD_QUALIFIER cerr << "==Parsing== " << xmlFile << XERCES_STD_QUALIFIER endl; } } else break; } else { xmlFile = argV[argInd]; more = false; } //reset error count first errorHandler.resetErrors(); XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc = 0; try { // reset document pool parser->resetDocumentPool(); const unsigned long startMillis = XMLPlatformUtils::getCurrentMillis(); doc = parser->parseURI(xmlFile); const unsigned long endMillis = XMLPlatformUtils::getCurrentMillis(); duration = endMillis - startMillis; } catch (const XMLException& toCatch) { XERCES_STD_QUALIFIER cerr << "\nError during parsing: '" << xmlFile << "'\n" << "Exception message is: \n" << StrX(toCatch.getMessage()) << "\n" << XERCES_STD_QUALIFIER endl; errorOccurred = true; continue; } catch (const DOMException& toCatch) { const unsigned int maxChars = 2047; XMLCh errText[maxChars + 1]; XERCES_STD_QUALIFIER cerr << "\nDOM Error during parsing: '" << xmlFile << "'\n" << "DOMException code is: " << toCatch.code << XERCES_STD_QUALIFIER endl; if (DOMImplementation::loadDOMExceptionMsg(toCatch.code, errText, maxChars)) XERCES_STD_QUALIFIER cerr << "Message is: " << StrX(errText) << XERCES_STD_QUALIFIER endl; errorOccurred = true; continue; } catch (...) { XERCES_STD_QUALIFIER cerr << "\nUnexpected exception during parsing: '" << xmlFile << "'\n"; errorOccurred = true; continue; } } // // Delete the parser itself. Must be done prior to calling Terminate, below. // parser->release(); // And call the termination method XMLPlatformUtils::Terminate(); if (doList) fin.close(); return errorOccurred || errorHandler.getSawErrors() ? 1 : 0; } XSDValidErrorHandler::XSDValidErrorHandler() : fSawErrors(false) { } XSDValidErrorHandler::~XSDValidErrorHandler() { } // --------------------------------------------------------------------------- // XSDValidHandlers: Overrides of the DOM ErrorHandler interface // --------------------------------------------------------------------------- bool XSDValidErrorHandler::handleError(const DOMError& domError) { fSawErrors = true; if (domError.getSeverity() == DOMError::DOM_SEVERITY_WARNING) { XERCES_STD_QUALIFIER cerr << "\nWarning at file "; } else if (domError.getSeverity() == DOMError::DOM_SEVERITY_ERROR) { XERCES_STD_QUALIFIER cerr << "\nError at file "; } else { XERCES_STD_QUALIFIER cerr << "\nFatal Error at file "; } XERCES_STD_QUALIFIER cerr << StrX(domError.getLocation()->getURI()) << ", line " << domError.getLocation()->getLineNumber() << ", char " << domError.getLocation()->getColumnNumber() << "\n Message: " << StrX(domError.getMessage()) << XERCES_STD_QUALIFIER endl; return true; } void XSDValidErrorHandler::resetErrors() { fSawErrors = false; }