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()

Reply via email to