writing XML with Xerces 3.0.1 and C++ on windows

17,207

Solution 1

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

Solution 2

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

Solution 3

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)

?

Solution 4

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.

Share:
17,207
dangerousdave
Author by

dangerousdave

Updated on June 04, 2022

Comments

  • dangerousdave
    dangerousdave almost 2 years

    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();
    }
    
  • dangerousdave
    dangerousdave almost 14 years
    Thanks for the reply Garett, i call XMLString::fixURI to get the path into that format.
  • dangerousdave
    dangerousdave almost 14 years
    Here is the string that gets passed to LocalFileFormatTarget: "file:///c:/foo.xml"
  • Garett
    Garett almost 14 years
    What error message are you getting? I'm assuming you've wrapped this in a try/catch.
  • dangerousdave
    dangerousdave almost 14 years
    unable to open file 'file:///c:/foo.xml'
  • dangerousdave
    dangerousdave almost 14 years
    Interesting, I tried what you suggested, it works fine for relative paths, but i get the same exception for absolute paths. "unable to open file 'c:\foo.xml'" simplified my code though, thankyou!
  • Garett
    Garett almost 14 years
    Have you tried using GetLastError() along with FormatMessage to get the windows error description? I tried it with you code and I got "The filename, directory name, or volume label syntax is incorrect"
  • jon-hanson
    jon-hanson almost 14 years
    Are you linking to a debug build of xerces? You should be able to step into the function i mention above add see the call to the Windows CreateFileW function.
  • dangerousdave
    dangerousdave almost 14 years
    Hi Garett, i tried your code above under visual studio 2008, and i still get Error Message: unable to open file 'C:/Foo.xml'. just to confirm, this code is working for you?
  • Garett
    Garett almost 14 years
    Yes, it is working for me. The error you are getting is the xerces error. To know what the windows error is, you will need to use dthe GetLastError and FormatMessage Windows API functions. stackoverflow.com/questions/455434/…. Also, as Jon indicated if you are linking against the debug build of the library you should be able to step into the function.