writing XML with Xerces 3.0.1 and C++ on windows
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.
dangerousdave
Updated on June 04, 2022Comments
-
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 almost 14 yearsThanks for the reply Garett, i call XMLString::fixURI to get the path into that format.
-
dangerousdave almost 14 yearsHere is the string that gets passed to LocalFileFormatTarget: "file:///c:/foo.xml"
-
Garett almost 14 yearsWhat error message are you getting? I'm assuming you've wrapped this in a try/catch.
-
dangerousdave almost 14 yearsunable to open file 'file:///c:/foo.xml'
-
dangerousdave almost 14 yearsInteresting, 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 almost 14 yearsHave 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 almost 14 yearsAre 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 almost 14 yearsHi 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 almost 14 yearsYes, 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.