I am new to Xalan and Xerces and I try to select one specific node by an XPath. It should be possible to return the xml data by reference but also need to be changed - thats why I saved it as DOMDocument to be able to access the data via xerces to manipulate them. I have two methods one to read an xml file and do schema validation and one to get a specific node. I am working with Visual Studio 2012 and of course the Xalan and Xerces libraries. I Tried to create one SSCCE to show you my problem:
Headerfile:
#pragma once
#include <string.h>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xalanc/Include/PlatformDefinitions.hpp>
#include <xalanc/XalanTransformer/XalanTransformer.hpp>
XALAN_CPP_NAMESPACE_USE
XERCES_CPP_NAMESPACE_USE
namespace CodeTest{
class Test
{
public:
Test(std::string schemaFilePath, std::string xmlFilePath){
mSchemaFilePath = schemaFilePath;
mXMLFilePath = xmlFilePath;
XMLPlatformUtils::Initialize();
XalanTransformer::initialize();
readXMLFile();
}
~Test(){
XalanTransformer::terminate();
XMLPlatformUtils::Terminate();
}
const XalanNode* getNode(XalanDOMString& path)const;
private:
Test();
Test(const Test&);
void readXMLFile();
std::string mSchemaFilePath;
std::string mXMLFilePath;
DOMDocument* mXMLDocument;
DOMElement* mRootElement;
XalanDocument* mXalanDocument;
XalanDocument* convertXercesDomDocumentToXalanDocument();
};
}
Source file:
#include "Test.h"
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xalanc/XPath/XPath.hpp>
#include <xalanc/XPath/XPathEvaluator.hpp>
#include <xalanc/XercesParserLiaison/XercesParserLiaison.hpp>
#include <xalanc/XercesParserLiaison/XercesDOMSupport.hpp>
#include <xalanc/XalanTransformer/XercesDOMWrapperParsedSource.hpp>
namespace CodeTest{
void Test::readXMLFile(){
XercesDOMParser xmlParser;
if (xmlParser.loadGrammar(mSchemaFilePath.c_str(), Grammar::SchemaGrammarType) == NULL){
fprintf(stderr, "couldn't load schema\n");
return;
}
xmlParser.setValidationScheme(XercesDOMParser::Val_Auto);
xmlParser.setDoNamespaces(true);
xmlParser.setDoSchema(true);
xmlParser.setValidationConstraintFatal(true);
xmlParser.parse(mXMLFilePath.c_str());
mXMLDocument = xmlParser.adoptDocument();
mXMLDocument->normalize();
mRootElement = mXMLDocument->getDocumentElement();
}
const XalanNode* Test::getNode(XalanDOMString& path)const{
XPathEvaluator theEvaluator;
XercesParserLiaison theParserLiaison;
XercesDOMSupport theDOMSupport(theParserLiaison);
XSLTInputSource xmlInput = mXMLFilePath.c_str();
XercesDOMWrapperParsedSource parsedSource(mXMLDocument, theParserLiaison, theDOMSupport, XalanDOMString(xmlInput.getSystemId()));
XalanDocument* xalanDocument = parsedSource.getDocument();
const XalanNode* node = theEvaluator.selectSingleNode(theDOMSupport, xalanDocument, path.c_str());
return node;
}
}
and my main function:
#include "Test.h"
#include <string.h>
int main(){
std::string schemaFile = "d:/testDate.xsd";
std::string xmlFile = "d:/test.xml";
CodeTest::Test xmlParser(schemaFile, xmlFile);
XalanDOMString path("personnel/person[1]");
const XalanNode* node = xmlParser.getNode(path);
return 0;
}
The problem is that I need to return the node with all its properties by reference. But the Problem is that the nod is only a local pointer which is invalid if he is out of scope. I already tried to save it as member variable but the ownership of the pointer belongs to XercesDOMWrapperParsedSource and I am not able to create this one as global variable because I receive the error message that the default constructor is private.
So I hope anyone of you can give me some advice.
You can't keep just XalanNode * and forget all the rest. If you want to pass XmlNode around your application you have to encapsulate it into your own class that will be internally holding all what the XalanNode * needs.
To demonstrate this I am going to attach few auxiliary files that I use in my project. These files will be pasted "as is", i.e. you are probably going to struggle a bit with their compilation as they are part of a bigger project and have some dependencies that I will omit (like boost logging, boost::filesystem::path; you can get rid easily of these dependencies). Yet, if someone needs it, so I believe that they will be easy to adapt it for your project and understand the idea.
The provided classes are meant to load a xml document into memory and allow to read it using XPath expressions.
Here is an example of usage of my classes.
And here go the included classes (sorry if this is not to best way to attach something bigger on this site)
The main implementation is in XalanXmlDoc that holds all the context but is not copyable. The XmlDoc and XmlNode do conveniently wrap XalanXmlDoc so that the document or nodes can be easily passed around the application.
tools/xalan/XercesRegistration.h
tools/xalan/XercesRegistration.cpp
tools/xalan/XalanRegistration.h
tools/xalan/XalanRegistration.cpp
tools/xalan/XmlDoc.h
tools/xalan/XmlDoc.cpp
tools/xalan/XmlNode.h
tools/xalan/XmlNode.cpp
XmlDoc.fwd.h
XmlNode.fwd.h
XalanXmlDoc.h
XalanXmlDoc.cpp