I have been maintaining a legacy system that uses Xerces-C++ for XML parsing. I have to use Xalan-C++ to achieve full XPath support. I am using Xerces-C++ 3.2.3 and Xalan-C++ 1.12.0 - these versions are compatible with each other
I have been having issues with some code that I wrote based on this example guide: http://www.xatlantis.ch/index.php/blog/19-xml/26-x-path-with-xerces-and-xalan
I have checked other examples, but the above example is the only one I found that uses the XercesDOMParser wrapper. Other examples (including the one provided by Xalan-C++) use Xalan's own DOM implementation. I could technically use that as a very last resort, but I would very much prefer to use the Xerces DOM wrapper.
Here is a snippet of my code:
std::string xpath = "/some/path/with/namespaces";
const xalanc::XalanDOMString strExpression(xpath.c_str());
xercesc::DOMDocument* document = xml.parser().get().getDocument();
xercesc::DOMNode* root = document->getDocumentElement();
xalanc::XercesParserLiaison parserLiaison;
parserLiaison.setBuildWrapperNodes(true);
parserLiaison.setBuildMaps(true);
xalanc::XalanDocument* xalanDocument = parserLiaison.createDocument(document, false, false);
xalanc::XalanElement* documentElement = xalanDocument->getDocumentElement();
xalanc::XercesDocumentWrapper* xercesDocumentWrapper = parserLiaison.mapDocumentToWrapper(xalanDocument);
xalanc::XalanNode* rootContextNode = xercesDocumentWrapper->mapNode(root);
xalanc::XercesDOMSupport domSupport(parserLiaison);
if(rootContextNode != NULL) {
xalanc::XPathEvaluator evaluator;
xalanc::XalanNode* foundXalanNode = evaluator.selectSingleNode(
domSupport,
rootContextNode,
strExpression.c_str(),
documentElement);
xercesc::DOMNode* targetNode = NULL;
if(foundXalanNode != NULL) {
xercesc::DOMNode const* constTargetNode = xercesDocumentWrapper->mapNode(foundXalanNode);
targetNode = const_cast<xercesc::DOMNode*>(constTargetNode);
std::cout << "value: " << targetNode->getNodeValue() << std::endl;
}
}
This is the smallest snippet of code I could write to reproduce my problem, I apologise if it feels too big. Let me know if you need clarification on any part of it.
This code compiles successfully, but it does not output anything and it should output the value of an input element. Under further investigation, it seems that foundXalanNode is NULL, which tells me that the code is unable to find a node that matches my xpath. I tested the xpath expression I am using in an online browser, and it is correct. I also tested different variations of the xpath without namespaces.
Edit: As requested, here is an example XML:
<?xml version="1.0" ?>
<ns3:header created="2022-04-07T14:19:55.611+01:00" schemaVersion="1.0.0" xmlns="example.org" xmlns:ns2="example.org" xmlns:ns3="example.org">
<ns3:point schemaVersion="1.1.0">
<ns2:type>PRODUCTION</ns2:type>
</ns3:point>
</ns3:header>
and here is the XPath I have been testing it with:
/ns3:header/ns3:point/ns2:type
I have tried to adapt the sample I mentioned in the comment to incorporate a Xerces DOM document and have Xalan wrap it; then I have run it against your sample XML with the arguments sample.xml / /ns3:header/ns3:point/ns2:type
and the output is e.g. content: PRODUCTION
, meaning the node is found.
The code is
#include <xalanc/Include/PlatformDefinitions.hpp>
#include <cassert>
#include <iostream>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xalanc/PlatformSupport/XSLException.hpp>
#include <xalanc/DOMSupport/XalanDocumentPrefixResolver.hpp>
#include <xalanc/XPath/XObject.hpp>
#include <xalanc/XPath/XPathEvaluator.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeDOMSupport.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeInit.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeParserLiaison.hpp>
//#include <parser.h>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xalanc/XercesParserLiaison/XercesDocumentWrapper.hpp>
using namespace XERCES_CPP_NAMESPACE;
int
main(
int argc,
char* argv[])
{
using std::cerr;
using std::cout;
using std::endl;
int theResult = 0;
if (argc != 4)
{
cerr << "Usage: SimpleXPathAPI XMLFilePath Context XPathExpression" << endl;
theResult = -1;
}
else
{
using xalanc::XSLException;
try
{
using xercesc::XMLPlatformUtils;
using xalanc::XPathEvaluator;
XMLPlatformUtils::Initialize();
XPathEvaluator::initialize();
{
using xercesc::LocalFileInputSource;
using xalanc::XalanDocument;
using xalanc::XalanDocumentPrefixResolver;
using xalanc::XalanDOMString;
using xalanc::XalanNode;
//using xalanc::XalanSourceTreeInit;
//using xalanc::XalanSourceTreeDOMSupport;
//using xalanc::XalanSourceTreeParserLiaison;
using xalanc::XObjectPtr;
XercesDOMParser* parser = new XercesDOMParser;
parser->setDoNamespaces(true);
parser->parse(argv[1]);
DOMDocument* doc = parser->getDocument();
xalanc::XercesParserLiaison parserLiaison;
parserLiaison.setBuildWrapperNodes(true);
parserLiaison.setBuildMaps(true);
xalanc::XercesDOMSupport domSupport(parserLiaison);
// Initialize the XalanSourceTree subsystem...
//XalanSourceTreeInit theSourceTreeInit;
// We'll use these to parse the XML file.
//XalanSourceTreeDOMSupport theDOMSupport;
//XalanSourceTreeParserLiaison theLiaison(theDOMSupport);
// Hook the two together...
//theDOMSupport.setParserLiaison(&theLiaison);
//const XalanDOMString theFileName(argv[1]);
// Create an input source that represents a local file...
//const LocalFileInputSource theInputSource(theFileName.c_str());
// Parse the document...
XalanDocument* const theDocument = parserLiaison.createDocument(doc, false, false);
//theLiaison.parseXMLStream(theInputSource);
assert(theDocument != 0);
xalanc::XercesDocumentWrapper* xercesDocumentWrapper = parserLiaison.mapDocumentToWrapper(theDocument);
XalanDocumentPrefixResolver thePrefixResolver(theDocument);
XPathEvaluator theEvaluator;
// OK, let's find the context node...
XalanNode* const theContextNode =
theEvaluator.selectSingleNode(
domSupport,
theDocument,
XalanDOMString(argv[2]).c_str(),
thePrefixResolver);
if (theContextNode == 0)
{
cerr << "Warning -- No nodes matched the location path \""
<< argv[2]
<< "\"."
<< endl
<< "Execution cannot continue..."
<< endl
<< endl;
}
else
{
xalanc::XPathEvaluator evaluator;
xalanc::XalanNode* foundXalanNode = theEvaluator.selectSingleNode(
domSupport,
theContextNode,
XalanDOMString(argv[3]).c_str(),
thePrefixResolver);
xercesc::DOMNode* targetNode = NULL;
if (foundXalanNode != NULL) {
xercesc::DOMNode const* constTargetNode = xercesDocumentWrapper->mapNode(foundXalanNode);
targetNode = const_cast<xercesc::DOMNode*>(constTargetNode);
std::cout << "content: " << XMLString::transcode(targetNode->getTextContent(), XMLPlatformUtils::fgMemoryManager) << std::endl;
}
}
}
XPathEvaluator::terminate();
XMLPlatformUtils::Terminate();
}
catch(const XSLException& theException)
{
using xalanc::XalanDOMString;
XalanDOMString theError;
cerr << "XSL exception: "
<< theException.defaultFormat(theError)
<< endl;
theResult = -1;
}
catch(...)
{
cerr << "Generic exception caught!" << endl;
theResult = -1;
}
}
return theResult;
}
I have used Xalan 1.12 and Xerces 3.2.3. No idea where your approach fails but hopefully the above helps you on your way to get your Xalan XPath evaluation against a Xerces DOM working.