// --------------------------------------------------------------------------- // // THIS PRODUCT CONTAINS "RESTRICTED MATERIALS OF IBM" // COPYRIGHT = 5748-T14 (C) COPYRIGHT IBM CORP 2001 // LICENSED MATERIAL - PROGRAM PROPERTY OF IBM // ALL RIGHTS RESERVED // US GOVERNMENT USERS RESTRICTED RIGHTS - // USE, DUPLICATION OR DISCLOSURE RESTRICTED BY // GSA ADP SCHEDULE CONTRACT WITH IBM CORP. // // --------------------------------------------------------------------------- // // START OF APAR HISTORY // // APAR DATE DESCRIPTION // PJ28176 20011005 Updated for the XML tutorial - XML4C vs. 3.5.1 // // PJ27634 20010327 Created for the XML tutorial - XML4C vs. 3.1.2 // // END OF APAR HISTORY // // --------------------------------------------------------------------------- // This application invokes the SAXParser. It uses various SAX handlers for // the specified XML input file. It will compare the requested element // name to the parsed elements and for those that match, it will display // the data content. // // The -e=element name parameter and filename are required. // // The parameters are: // // -e=element Specific element name for searching // -v=xxx Validation scheme (always | never | auto) // -n Enable namespace processing. Default is off // -s Enable schema processing. Default is off // -? Show usage and exit // filename Path to the XML file to parse // // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include //**************************************************************************** // // You can view the documentation for the DOM and SAX APIs by // clicking the 'XML4C Version 3.1.2 Documentation' from // XML on TPF: An Online User's Guide. // //**************************************************************************** class SAXSearchHandlers : public HandlerBase { public: // ----------------------------------------------------------------------- // Constructors // ----------------------------------------------------------------------- SAXSearchHandlers(); ~SAXSearchHandlers(); // ----------------------------------------------------------------------- // Implementations of the SAX DocumentHandler interface // ----------------------------------------------------------------------- void endDocument(); void endElement(const XMLCh* const name); void characters(const XMLCh* const chars, const unsigned int length); void ignorableWhitespace ( const XMLCh* const chars , const unsigned int length ); void processingInstruction ( const XMLCh* const target , const XMLCh* const data ); void startDocument(); void startElement(const XMLCh* const name, AttributeList& attributes); // ----------------------------------------------------------------------- // Implementations of the SAX ErrorHandler interface // ----------------------------------------------------------------------- void warning(const SAXParseException& exception); void error(const SAXParseException& exception); void fatalError(const SAXParseException& exception); }; // --------------------------------------------------------------------------- // SAXSearchHandlers: Constructors and Destructor // --------------------------------------------------------------------------- SAXSearchHandlers::SAXSearchHandlers() { } SAXSearchHandlers::~SAXSearchHandlers() { } // --------------------------------------------------------------------------- // Local data // // xmlFile // The path to the file to parse obtained from the command line. // // doValidation // Indicates whether the validating or non-validating parser should be // used. // // doNamespaces // Indicates whether namespace processing should be enabled or not. // Defaults to disabled. // // doSchema // Indicates whether schema processing should be enabled or not. // Defaults to disabled. // // elementName // The element name to search for in the xmlFile. // // foundMatch // Indicates whether the requested element name is found in the xml // file. // // doElement // Used to track the beginning of the start element so that nested // elements will be included in the display. // // --------------------------------------------------------------------------- static char* xmlFile = 0; static bool doValidation = false; static char* elementName = 0; static bool foundMatch = false; static bool doElement = false; static bool doNamespaces = false; static bool doSchema = false; char* eMessage = 0; static SAXParser::ValSchemes valScheme = SAXParser::Val_Auto; // --------------------------------------------------------------------------- // Local help methods // --------------------------------------------------------------------------- static void usage() { cout << "\nUsage: saxxml (parameters) -e=element filename\n" << " This program prints the data returned by various SAX\n" << " handlers for the requested element name from a specified\n" << " input file.\n\n" << " The -e=element name parameter and filename are required.\n\n" << " Parameters:\n" << " -e=element Element name for searching. \n" << " -v=xxx Validation scheme (always | never | auto*)\n" << " -n Enable namespace processing.\n" << " -s Enable schema processing.\n" << " -? Show this help\n" << endl; } // --------------------------------------------------------------------------- // Main entry point // --------------------------------------------------------------------------- int main(int argC, char* argV[]) { unsigned int argIndex = 0; // Initialize the XML4C system try { XMLPlatformUtils::Initialize(); } catch (const XMLException& toCatch) { eMessage = XMLString::transcode(toCatch.getMessage()); cerr << "Error during initialization! :\n" << eMessage << endl; delete [] eMessage; return 1; } // Check command line and extract arguments. if (argC < 2) { usage(); return 1; } // Watch for help request if (strcmp(argV[1], "-?") == 0) { usage(); return 0; } for (argIndex = 1; argIndex < (unsigned int)argC; argIndex++) { // Break on first parameter that does not start with a dash if (argV[argIndex][0] != '-') break; if (!strncmp(argV[argIndex], "-v=", 3) || !strncmp(argV[argIndex], "-V=", 3)) { const char* const parm = &argV[argIndex][3]; if (!strcmp(parm, "never")) valScheme = SAXParser::Val_Never; else if (!strcmp(parm, "auto")) valScheme = SAXParser::Val_Auto; else if (!strcmp(parm, "always")) valScheme = SAXParser::Val_Always; else { cerr << "Unknown -v= value: " << parm << endl; return 2; } } else if (!strcmp(argV[argIndex], "-n") || !strcmp(argV[argIndex], "-N")) { doNamespaces = true; } else if (!strcmp(argV[argIndex], "-s") || !strcmp(argV[argIndex], "-S")) { doSchema = true; } else if (!strncmp(argV[argIndex], "-e=",3) || !strncmp(argV[argIndex], "-E=",3)) { elementName = &argV[argIndex][3]; } // display usage help else { usage(); return 1; } } if (!elementName) // element name is required { usage(); return 1; } // // We have to have only one parameter left and it must be // the file name. // if (argIndex + 1 != (unsigned int)argC) { usage(); return 1; } xmlFile = argV[argIndex]; // // Create a SAX parser object and set it to validate or not which was // determined from the command line. // SAXParser parser; parser.setValidationScheme(valScheme); parser.setDoNamespaces(doNamespaces); parser.setDoSchema(doSchema); // // Create the handler object and install it as the document and error // handler for the parser. // SAXSearchHandlers handler; parser.setDocumentHandler(&handler); parser.setErrorHandler(&handler); // Parse the file and catch any exceptions that are thrown try { parser.parse(xmlFile); } catch (const XMLException& toCatch) { eMessage = XMLString::transcode(toCatch.getMessage()); cerr << "\nFile not found: '" << xmlFile << "'\n" << "Exception message is: \n" << eMessage << endl << "\n" << endl; delete [] eMessage; return -1; } return 0; } // --------------------------------------------------------------------------- // SAXSearchHandlers: Overrides of the SAX DocumentHandler interface // // DocumentHandler defines events related to the document itself // (opening and closing tags, content of elements, etc). The SAX // interface allows the application to register handlers for these // different types of events. // // As the event-based parser reads the XML document, it will send // events which alert the application. If you want to react to a // particular event(s), you register event handlers which are functions // that process the events. // // For example: The XML parser will create an event for each element // opening tag. If your application needs to do some processing based // on the element, then you would set up a handler for the method // startElement(). Similarly, the characters() method is used to // notify the application when the parser finds content or text in an // element. // // XML provides support for the Unicode standard character set. // Since Unicode supports all spoken languages, plus other symbols // it needs more than 8 bits per character. // // XML4C uses XMLCh as the fundamental type that needs to be defined // to be big enough to hold one Unicode character...on TPF XMLCh is // defined as two-bytes. // // Since all processing in the XML parser happens in Unicode, we need to // translate the parser data from Unicode (XMLCh) to TPF's default (native) // code-page or character set (IBM-1047). That enables the application to // handle the content in the proper character set for its system (ebcdic). // This is done by using XMLString::transcode(). // // On TPF, the default or local code page is defined as IBM-1047 and is // set in /xml/src/util/Transcoders/IconvTPF/IconvTPFTransService.cpp. // All transcoding will use this value. // // --------------------------------------------------------------------------- void SAXSearchHandlers::characters(const XMLCh* const chars , const unsigned int length) { if (doElement) { // Transcode to IBM-1047 for display char* tmpText = XMLString::transcode(chars); // Display the text for (unsigned int index = 0; index < length; index++) { switch (tmpText[index]) { case ' ' : // ignore all whitespace and new lines case '\n' : break; default: cout << tmpText[index]; break; } } delete [] tmpText; } } void SAXSearchHandlers::endDocument() { if (!foundMatch) cout << "There is no data because the element name was not found" << endl; } void SAXSearchHandlers::endElement(const XMLCh* const name) { char *nString = XMLString::transcode(name); if (!XMLString::compareString(nString,elementName)) { doElement = false; cout << endl; } if (doElement) cout << endl; delete [] nString; } void SAXSearchHandlers::ignorableWhitespace( const XMLCh* const chars ,const unsigned int length) { // Validating parsers must use this method to report each chunk // of ignorable whitespace. } void SAXSearchHandlers::processingInstruction(const XMLCh* const target , const XMLCh* const data) { if (doElement) { char *tString = XMLString::transcode(target); cout << tString; delete [] tString; if (data) { char *dString = XMLString::transcode(data); cout << dString; delete [] dString; } } } void SAXSearchHandlers::startDocument() { cout << endl << "Element \"" << elementName << "\" contains the following data:" << endl << endl; } void SAXSearchHandlers::startElement(const XMLCh* const name , AttributeList& attributes) { // // Transcode the parser element name to TPF's default code page. // Since the parsed element name is in Unicode, we need to // translate it from XMLCh to IBM-1047. // // That enables us to compare the parser element name to // the requested element name obtained from the command line // which is in IBM-1047. This transcoding or translation is // done by the using XMLString::transcode(). // // doElement is a flag used to track the beginning of a matched // element name so that the nested elements (which will not match) // are still considered part of the display. // unsigned int len, index; char *nString = XMLString::transcode(name); if (!XMLString::compareString(nString,elementName)) { doElement = true; foundMatch = true; len = attributes.getLength(); for (index = 0; index < len; index++) { char *aString = XMLString::transcode(attributes.getValue(index)); cout << aString << endl; delete [] aString; } } else { if (doElement) { len = attributes.getLength(); for (index = 0; index < len; index++) { char *aString = XMLString::transcode(attributes.getValue(index)); cout << aString << endl; delete [] aString; } } } delete [] nString; } // --------------------------------------------------------------------------- // SAXSearchErrorHandlers: Overrides of the SAX ErrorHandler interface // // The SAXParseException method encapsulates an XML parser error or warning. // It will include information for locating the error in the XML document. // The user installs SAX Error Handler methods: 'fatalError, 'error', 'warning' // depending on the severity of the error. The parser will use this callback // mechanism to report the error condition. // // If the application needs to reports errors is a special way, that // customization would be done here using these methods. // // --------------------------------------------------------------------------- void SAXSearchHandlers::error(const SAXParseException& e) { char *eSysId = XMLString::transcode(e.getSystemId()); eMessage = XMLString::transcode(e.getMessage()); cerr << "\nError at (file " << eSysId << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << eMessage << endl; delete [] eSysId; delete [] eMessage; } void SAXSearchHandlers::fatalError(const SAXParseException& e) { char *eSysId = XMLString::transcode(e.getSystemId()); eMessage = XMLString::transcode(e.getMessage()); cerr << "Fatal Error at file \"" << eSysId << "\", line " << e.getLineNumber() << ", column " << e.getColumnNumber() << "): " << eMessage << endl; delete [] eSysId; delete [] eMessage; } void SAXSearchHandlers::warning(const SAXParseException& e) { char *eSysId = XMLString::transcode(e.getSystemId()); eMessage = XMLString::transcode(e.getMessage()); cerr << "\nWarning at (file " << eSysId << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << "): " << eMessage << endl; delete [] eSysId; delete [] eMessage; }