// --------------------------------------------------------------------------- // // 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 DOMParser to build a DOM tree for the // specified input file. It gets a node list of elements that match the // element name search request. Then it traverses through the list and prints // out the content. // // The -e=element name parameter and filename are required. // // The parameters are: // // -? - Show usage and exit // -v=xxx - Validation scheme [always | never | auto* // -n - Enable namespace processing. Default is off // -s - Enable schema processing. Default is off // -e=element name - Element name for searching // filename - Path to the XML file to parse // // // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #include #include #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 DOMSearchErrorReporter : public ErrorHandler { public: // ----------------------------------------------------------------------- // Constructors and Destructor // ----------------------------------------------------------------------- DOMSearchErrorReporter() { } ~DOMSearchErrorReporter() { } // ----------------------------------------------------------------------- // Implementation of the error handler interface // ----------------------------------------------------------------------- void warning(const SAXParseException& toCatch); void error(const SAXParseException& toCatch); void fatalError(const SAXParseException& toCatch); void resetErrors(); }; // --------------------------------------------------------------------------- // Forward references // --------------------------------------------------------------------------- void displayContent(const DOMString &s); void usage(); void processElement (DOM_Node& toDisplay); // --------------------------------------------------------------------------- // Local data // // xmlFile // The path to the file to parse obtained from the command line. // // doValidation // Indicates whether validation should be done. The default is not // to validate, but -v overrides that. // // 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. // // --------------------------------------------------------------------------- static char* elementName = 0; static char* xmlFile = 0; static bool doNamespaces = false; static bool doSchema = false; char* eMessage = 0; static DOMParser::ValSchemes valScheme = DOMParser::Val_Auto; // --------------------------------------------------------------------------- // Main entry point // --------------------------------------------------------------------------- int main(int argC, char* argV[]) { // Initialize the XML4C system try { XMLPlatformUtils::Initialize(); } catch(const XMLException& toCatch) { eMessage = XMLString::transcode(toCatch.getMessage()); cerr << "Error during initialization.\n" << " Exception message:" << eMessage << endl; delete [] eMessage; return 1; } // Extract command line arguments. if (argC < 2) { usage(); return 1; } // Check for help request if (strcmp(argV[1], "-?") == 0) { usage(); return 0; } // See if non validating or validating DOM parser is requested. int argIndex; for (argIndex = 1; argIndex < argC; argIndex++) { // break on first parameter not starting 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 = DOMParser::Val_Never; else if (!strcmp(parm, "auto")) valScheme = DOMParser::Val_Auto; else if (!strcmp(parm, "always")) valScheme = DOMParser::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]; } else { usage(); return 1; } } if (!elementName) // element name is required { usage(); return 1; } // // Now we have to have only one parameter left and it must be // the file name. // if (argIndex + 1 != argC) { usage(); return 1; } xmlFile = argV[argIndex]; // // Create our validator with the API setValidationScheme. // Then attach an error handler to the parser with API setErrorHandler. // The parser will call back to methods of the ErrorHandler if it // discovers errors during the course of parsing the XML document. // DOMParser *parser = new DOMParser; parser->setValidationScheme(valScheme); parser->setDoNamespaces(doNamespaces); parser->setDoSchema(doSchema); ErrorHandler *errReporter = new DOMSearchErrorReporter(); parser->setErrorHandler(errReporter); parser->setToCreateXMLDeclTypeNode(true); // // Parse the XML file, catching any XML exceptions that might be thrown // out of it. // bool errorsOccured = false; try { parser->parse(xmlFile); } catch (const XMLException& e) { eMessage = XMLString::transcode(e.getMessage()); cerr << "\nError during parsing: '" << xmlFile << "'\n" << "Exception message is: \n" << eMessage << endl; delete [] eMessage; errorsOccured = true; } // --------------------------------------------------------------------------- // Processing for the -e element name option. // First, get the list of elements from the DOM tree that match the request. // Then traverse through the list and display the content. // --------------------------------------------------------------------------- if ((elementName) && (!errorsOccured)) { DOM_Document document = parser->getDocument(); DOM_NodeList n1 = document.getElementsByTagName(elementName); DOM_Node child; if (n1.getLength() == 0) cout << endl << "Element \"" << elementName << "\" cannot be found" << endl << endl; else cout << endl << "Element \"" << elementName << "\" contains the following data:" << endl << endl; for (int i=0; i < n1.getLength(); i++) { child = n1.item(i); processElement (child); } } // // Clean up the error handler object. // delete errReporter; // // The DOM document and its contents are reference counted and need // no explicit deletion. // return 0; } // --------------------------------------------------------------------------- // // Usage() // // --------------------------------------------------------------------------- void usage() { cout << "\nUsage: domxml (parameters) -e=element filename\n" " This program invokes the XML4C DOM parser and builds the \n" " DOM tree. It then creates a node list for all the elements\n" " that match the requested element name\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. Default is off.\n" " -s Enable schema processing. Default is off.\n" " -? Show this help \n" << endl; } // --------------------------------------------------------------------------- // Walk the element tree // // This function is called for every element that matches the // the request from the command line. It will display each DOM node // by recursively calling itself for all children of the current node. // Since children are nodes, visiting them means visitng their children, // and the children of their children, and so on. // // This function is the basis for walking a DOM tree. Pass in a node // and it will do the entire thing. For this application, not all // nodes will have specific processing but it could be used to process // all nodes from the top of the tree to the end. // // --------------------------------------------------------------------------- void processElement (DOM_Node& toDisplay) { // Get the name and value for everyone to use DOMString nodeName = toDisplay.getNodeName(); DOMString nodeValue = toDisplay.getNodeValue(); char *displayData=0; switch (toDisplay.getNodeType()) { case DOM_Node::TEXT_NODE: { displayContent (nodeValue); break; } case DOM_Node::ELEMENT_NODE : { // Output any attributes on this element DOM_NamedNodeMap attributes = toDisplay.getAttributes(); int attrNum = attributes.getLength(); for (int i = 0; i < attrNum; i++) { DOM_Node attribute = attributes.item(i); displayData = attribute.getNodeValue().transcode(); cout << displayData << endl; delete [] displayData; } // // Test for children which includes both // text content and nested elements. // DOM_Node child = toDisplay.getFirstChild(); if (child != 0) { // Output children. while( child != 0) { processElement(child); child = child.getNextSibling(); } // Done with children. } // // If there were no children then this is an empty element. // cout << endl; break; } case DOM_Node::PROCESSING_INSTRUCTION_NODE : { displayData = nodeName.transcode(); cout << displayData << ' '; delete [] displayData; displayData = nodeValue.transcode(); cout << displayData; delete [] displayData; break; } case DOM_Node::CDATA_SECTION_NODE: { displayData = nodeValue.transcode(); cout << displayData; delete [] displayData; break; } case DOM_Node::DOCUMENT_NODE : { // // not used in this application // break; } case DOM_Node::ENTITY_REFERENCE_NODE: { // // not used in this application // break; } case DOM_Node::COMMENT_NODE: { displayData = nodeValue.transcode(); cout << displayData; delete [] displayData; break; } default: cerr << "Unrecognized node type = " << (long)toDisplay.getNodeType() << endl; } return; } // --------------------------------------------------------------------------- // // displayContent - Display data for requested element name. // // First, get raw data in Unicode format for this node value. // Loop through checking for whitespaces or line feed and ignore those. // For all other characters, transcode to the default code page and display. // // 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() or the transcode() method // of DOMString. // // 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 displayContent(const DOMString &nodeValue) { int length = nodeValue.length(); const XMLCh* nodeData = nodeValue.rawBuffer(); char *displayData; int index; for (index = 0; index < length; index++) { switch (nodeData[index]) { case chSpace : case chLF : break; default: displayData = nodeValue.substringData(index, 1).transcode(); cout << displayData; delete [] displayData; break; } } return; } // --------------------------------------------------------------------------- // DOMSearchErrorHandlers: Overrides of the SAX ErrorHandler interface // // If you use the standard parser classes, DOMParser or SAXParser, you // will use the mechanism by the SAX API called ErrorHandler that is // similar to XMLErrorReporter. // // 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 report errors is a special way, that // customization would be done here using these methods. // // --------------------------------------------------------------------------- void DOMSearchErrorReporter::warning(const SAXParseException&) { // // Ignore all warnings. // } void DOMSearchErrorReporter::error(const SAXParseException& toCatch) { char *eSysId = XMLString::transcode(toCatch.getSystemId()); eMessage = XMLString::transcode(toCatch.getMessage()); cerr << "Error at file \"" << eSysId << "\", line " << toCatch.getLineNumber() << ", column " << toCatch.getColumnNumber() << "\n Message: " << eMessage << endl; delete [] eSysId; delete [] eMessage; } void DOMSearchErrorReporter::fatalError(const SAXParseException& toCatch) { char *eSysId = XMLString::transcode(toCatch.getSystemId()); eMessage = XMLString::transcode(toCatch.getMessage()); cerr << "Fatal Error at file \"" << eSysId << "\", line " << toCatch.getLineNumber() << ", column " << toCatch.getColumnNumber() << "\n Message: " << eMessage << endl; delete [] eSysId; delete [] eMessage; } void DOMSearchErrorReporter::resetErrors() { // No-op in this application }