writing XML with Xerces 3.0.1 and C++ on windows

2020-02-29 06:49发布

i have the following function i wrote to create an XML file using Xerces 3.0.1, if i call this function with a filePath of "foo.xml" or "../foo.xml" it works great, but if i pass in "c:/foo.xml" then i get an exception on this line

XMLFormatTarget *formatTarget = new LocalFileFormatTarget(targetPath);

can someone explain why my code works for relative paths, but not absolute paths please? many thanks.

const int ABSOLUTE_PATH_FILENAME_PREFIX_SIZE = 9;

void OutputXML(xercesc::DOMDocument* pmyDOMDocument, std::string filePath)
{
    //Return the first registered implementation that has the desired features. In this case, we are after a DOM implementation that has the LS feature... or Load/Save.
    DOMImplementation *implementation = DOMImplementationRegistry::getDOMImplementation(L"LS");

    // Create a DOMLSSerializer which is used to serialize a DOM tree into an XML document.
    DOMLSSerializer *serializer = ((DOMImplementationLS*)implementation)->createLSSerializer();

    // Make the output more human readable by inserting line feeds.
    if (serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true))
        serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);

    // The end-of-line sequence of characters to be used in the XML being written out. 
    serializer->setNewLine(XMLString::transcode("\r\n")); 

    // Convert the path into Xerces compatible XMLCh*.
    XMLCh *tempFilePath = XMLString::transcode(filePath.c_str());

    // Calculate the length of the string.
    const int pathLen = XMLString::stringLen(tempFilePath);

    // Allocate memory for a Xerces string sufficent to hold the path.
    XMLCh *targetPath = (XMLCh*)XMLPlatformUtils::fgMemoryManager->allocate((pathLen + ABSOLUTE_PATH_FILENAME_PREFIX_SIZE) * sizeof(XMLCh));

    // Fixes a platform dependent absolute path filename to standard URI form.
    XMLString::fixURI(tempFilePath, targetPath);

    // Specify the target for the XML output.
    XMLFormatTarget *formatTarget = new LocalFileFormatTarget(targetPath);
    //XMLFormatTarget *myFormTarget = new StdOutFormatTarget();

    // Create a new empty output destination object.
    DOMLSOutput *output = ((DOMImplementationLS*)implementation)->createLSOutput();

    // Set the stream to our target.
    output->setByteStream(formatTarget);

    // Write the serialized output to the destination.
    serializer->write(pmyDOMDocument, output);

    // Cleanup.
    serializer->release();
    XMLString::release(&tempFilePath);
    delete formatTarget;
    output->release();
}

4条回答
ら.Afraid
2楼-- · 2020-02-29 07:02

Are you using Windows Vista? perhaps you don't have the necessary permissions? See this question: Exception in two line Xerces program

查看更多
虎瘦雄心在
3楼-- · 2020-02-29 07:04

It looks like your file path is incorrect. It should be file:///C:/. See the following for more information:

http://en.wikipedia.org/wiki/File_URI_scheme

UPDATE: The following code works for me with Visual Studio 2008. It's a quick hack using your code along with some sample that comes with Xerces.

#include <windows.h>
#include <iostream>
#include <string>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>
#include <xercesc/framework/XMLFormatter.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationRegistry.hpp>
#include <xercesc/dom/DOMLSSerializer.hpp>
#include <xercesc/dom/DOMLSOutput.hpp>


using namespace xercesc;
using namespace std;

void OutputXML(xercesc::DOMDocument* pmyDOMDocument, std::string filePath);

class XStr
{
public :
    XStr(const char* const toTranscode)
    {
        // Call the private transcoding method
        fUnicodeForm = XMLString::transcode(toTranscode);
    }

    ~XStr()
    {
        XMLString::release(&fUnicodeForm);
    }

    const XMLCh* unicodeForm() const
    {
        return fUnicodeForm;
    }

private :
    XMLCh*   fUnicodeForm;
};

#define X(str) XStr(str).unicodeForm()

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        XMLPlatformUtils::Initialize();
    }
    catch(const XMLException& e)
    {
        char* message = XMLString::transcode(e.getMessage());
        cout << "Error Message: " << message << "\n";
        XMLString::release(&message);
        return 1;
    }

    int errorCode = 0;
    {

        DOMImplementation* impl =  DOMImplementationRegistry::getDOMImplementation(X("Core"));

        if (impl != NULL)
        {
            try
            {
                DOMDocument* doc = impl->createDocument(
                               0,                    // root element namespace URI.
                               X("company"),         // root element name
                               0);                   // document type object (DTD).

                DOMElement* rootElem = doc->getDocumentElement();

                DOMElement*  prodElem = doc->createElement(X("product"));
                rootElem->appendChild(prodElem);

                DOMText*    prodDataVal = doc->createTextNode(X("Xerces-C"));
                prodElem->appendChild(prodDataVal);

                DOMElement*  catElem = doc->createElement(X("category"));
                rootElem->appendChild(catElem);

                catElem->setAttribute(X("idea"), X("great"));

                DOMText*    catDataVal = doc->createTextNode(X("XML Parsing Tools"));
                catElem->appendChild(catDataVal);

                DOMElement*  devByElem = doc->createElement(X("developedBy"));
                rootElem->appendChild(devByElem);

                DOMText*    devByDataVal = doc->createTextNode(X("Apache Software Foundation"));
                devByElem->appendChild(devByDataVal);

                OutputXML(doc, "C:/Foo.xml");

                doc->release();
            }
            catch (const OutOfMemoryException&)
            {
                XERCES_STD_QUALIFIER cerr << "OutOfMemoryException" << XERCES_STD_QUALIFIER endl;
                errorCode = 5;
            }
            catch (const DOMException& e)
            {
                XERCES_STD_QUALIFIER cerr << "DOMException code is:  " << e.code << XERCES_STD_QUALIFIER endl;
                errorCode = 2;
            }
            catch(const XMLException& e)
            {
                char* message = XMLString::transcode(e.getMessage());
                cout << "Error Message: " << message << endl;
                XMLString::release(&message);
                return 1;
            }
            catch (...)
            {
                XERCES_STD_QUALIFIER cerr << "An error occurred creating the document" << XERCES_STD_QUALIFIER endl;
                errorCode = 3;
            }
       }  // (inpl != NULL)
       else
       {
           XERCES_STD_QUALIFIER cerr << "Requested implementation is not supported" << XERCES_STD_QUALIFIER endl;
           errorCode = 4;
       }
    }

    XMLPlatformUtils::Terminate();

    return errorCode;
}

void OutputXML(xercesc::DOMDocument* pmyDOMDocument, std::string filePath) 
{ 
    //Return the first registered implementation that has the desired features. In this case, we are after a DOM implementation that has the LS feature... or Load/Save. 
    DOMImplementation *implementation = DOMImplementationRegistry::getDOMImplementation(L"LS"); 

    // Create a DOMLSSerializer which is used to serialize a DOM tree into an XML document. 
    DOMLSSerializer *serializer = ((DOMImplementationLS*)implementation)->createLSSerializer(); 

    // Make the output more human readable by inserting line feeds. 
    if (serializer->getDomConfig()->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true)) 
        serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true); 

    // The end-of-line sequence of characters to be used in the XML being written out.  
    serializer->setNewLine(XMLString::transcode("\r\n"));  

    // Convert the path into Xerces compatible XMLCh*. 
    XMLCh *tempFilePath = XMLString::transcode(filePath.c_str()); 

    // Specify the target for the XML output. 
    XMLFormatTarget *formatTarget = new LocalFileFormatTarget(tempFilePath); 

    // Create a new empty output destination object. 
    DOMLSOutput *output = ((DOMImplementationLS*)implementation)->createLSOutput(); 

    // Set the stream to our target. 
    output->setByteStream(formatTarget); 

    // Write the serialized output to the destination. 
    serializer->write(pmyDOMDocument, output); 

    // Cleanup. 
    serializer->release(); 
    XMLString::release(&tempFilePath); 
    delete formatTarget; 
    output->release(); 
} 
查看更多
淡お忘
4楼-- · 2020-02-29 07:05

Running the above code might give the error - 'DOMDocument' : ambiguous symbol, in which case replace DOMDocument by xercesc::DOMDocument as there is also a DOMDocument class defined in msxml.h header that leads to ambiguity.

查看更多
看我几分像从前
5楼-- · 2020-02-29 07:06

From looking at the source the filename gets passed through to WindowsFileMgr::fileOpen in WindowsFileMgr.cpp, which doesn't appear to be expecting a URI.

So, have you tried not converting the filename to a URI, e.g. just use:

c:\foo.xml

(might need to escape the backslash)

?

查看更多
登录 后发表回答