Hello all,
I'm writing a configuration utility that we call an "application profile" or simply profile, that is essentially an ini file on steroids. It's a hierarchical structure - application/section/item - that allows multiple applications to use a single profile. I'm migrating it from "key = value" format to XML and I'm using Xalan/Xerces for evaluating XPath expressions to retrieve the configuration items. >From a functional standpoint, the interface to the profile is: - open the profile (load the XML file, parse it into a DOM tree) - execute a getItem() call for each of the one or more items to be retrieved - close the profile After using the SimpleXPath... sample program to set up a working XPath evaluation, I tried splitting things up along open/read/close functional lines. That is, I tried reading the XML file and parsing it into a Xalan DOM tree in the open() method, doing the XPath evaluation in the getItem() method, and the terminate() functions in the close() method. To do this I had to put certain objects common to the open() and getItem() methods into Profile class member data, specifically the XalanDocument* and the XalanSourceTreeDOMSupport. The open() method runs successfully, parses the doc, and sets up the XalanDocument pointer. However, when I try to evaluate an XPath expression, the instantiation of the XalanDocumentPrefixResolver object fails with a "generic" exception, that is: XalanDocumentPrefixResolver thePrefixResolver(_pXmlDoc); where _pXmlDoc is in the Profile class private member data throws an exception caught by the (...) catch. The code for the methods in question is below. Is there a way to do what I'm trying to do? Can I, from inside what is essentially a wrapper class, open and parse a document into a DOM tree in one method, and then use the results of that method to execute one or more XPath evaluations against the DOM tree in another method? I'd really hate to have to parse the document every time a user makes a call to getItem(). Thanks in advance, any help would be most appreciated. Best, -will (code follows, catches and some other irrelevant stuff left out for brevity) int Profile::_openXmlDoc (const char* pXmlFilespec) { try { XMLPlatformUtils::Initialize(); XPathEvaluator::initialize(); { // Initialize the XalanSourceTree subsystem... XalanSourceTreeInit theSourceTreeInit; // We'll use these to parse the XML file. // now declared in private member data // XalanSourceTreeDOMSupport theDOMSupport; XalanSourceTreeParserLiaison theLiaison(_DomSupport); // Hook the two together... _DomSupport.setParserLiaison(&theLiaison); const XalanDOMString theFileName(pXmlFilespec); // Create an input source that represents a local file... const LocalFileInputSource theInputSource(theFileName.c_str()); // Parse the document... XalanDocument* const theDocument = theLiaison.parseXMLStream(theInputSource); if (theDocument == NULL) { ::sprintf(_zErr, "Error (%s): document parsing failed for file (%s)\n", pThisFnc, theFileName.c_str()); rc = E_ANY_ERROR; } else { /* set these member vars so the XPath stuff can use them */ _pXmlDoc = theDocument; } } } return (rc); } // end _open() int Profile::_getStringItem (const char* pAppName, const char* pSectionName, const char* pItemName, char* pBufRet, size_t& bufLen) { ::memset((void*)xpathExpr, 0, sizeof(xpathExpr)); ::sprintf(xpathExpr, pXPathTplt, pAppName, pSectionName, pItemName); try { // use the document pointer stored in member data // ** this statement throws an exception caught by the (...) catch XalanDocumentPrefixResolver thePrefixResolver(_pXmlDoc); XPathEvaluator theEvaluator; // OK, let's find the context node... using member data for DomSupport and pXmlDoc? // but we never get to this point XalanNode* const pContextNode = theEvaluator.selectSingleNode(_DomSupport, _pXmlDoc, XalanDOMString(pDfltContext).c_str(), thePrefixResolver); if (pContextNode == 0) { ::sprintf(_zErr, "Error (%s): No nodes matched the context path (%s)\n", pThisFnc, pDfltContext); rc = E_ANY_ERROR; } else { // OK, let's evaluate the expression... const XObjectPtr theResult(theEvaluator.evaluate(_DomSupport, pContextNode, XalanDOMString(xpathExpr).c_str(), thePrefixResolver)); if (theResult.null()) { /* a null result means we didn't find it, set the returned length to zero and set an error */ bufLen = 0; ::sprintf(_zErr, "Warning (%s): item not found, no node matched " "the XPath expression:\n (%s)\n", pThisFnc, xpathExpr); rc = E_ITEM_NOTFOUND; } else { /* we found something, jump through a couple of hoops to get it into a C-string, copy it to the return buffer, and set the returned length */ /* the transcode method transcodes the result string (UTF-16) to chars and stores them in a vector of chars. the chars from the vector are then assigned to a std::string object by iterating through the vector. once assigned to the string they are in a form we can use them. */ XalanVector<char> charData; std::string rtnStr; theResult->str().transcode(charData); rtnStr.assign(charData.begin(), charData.end()); /* clear the return buffer, copy the string in, and set the returned length */ ::memset((void*)pBufRet, 0, bufLen); ::strncpy(pBufRet, rtnStr.c_str(), bufLen - 1); pBufRet[bufLen - 1] = 0; bufLen = ::strlen(rtnStr.c_str()); } } } return (rc); } // end getItem()