Xalan-c++: returning a node with XPath (reference to local pointer)

1.7k views Asked by At

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.

1

There are 1 answers

0
David L. On

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.

#include "tools/xalan/XalanRegistration.h"
#include "tools/xalan/XmlDoc.h"
#include "tools/xalan/XmlNode.h"

tools::xalan::XmlNode do_stuff_and_get_node() {

    XmlDoc myDoc("file_to_load.xml");
    return myDoc.getNode("/path/to/my/node");

}

int main(){
    //this always goes to the main application scope
    tools::xalan::XalanRegistration xalan;

    //the rest may appear anywhere in your application

    const tools::xalan::XmlNode my_node = do_stuff_and_get_node();

    if (my_node.getBool("xpath/relative/to/my_node[@boolean_attr]")) {
        std::out << my_node.getString("xpath/relative/to/my_node/text()");
    }

    const tools::xalan::XmlNode other_node = my_node("other/node");

    //node holds internally the whole document so you can use also
    //absolute xpath
    auto more_nodes = other_node.getNodes("/i/want/more");
    for (const tools::xalan::XmlNode &node: more_nodes) {
        ...
    }
}

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

#ifndef TOOLS_XERCES_XERCESREGISTRATION_H_
#define TOOLS_XERCES_XERCESREGISTRATION_H_

#include "NS-OPEN"

class XercesRegistration {
public:

    /**
     * This constructor calls:
     * XMLPlatformUtils::Initialize();
     */
    XercesRegistration();

    /**
     * This destructor calls:
     * XMLPlatformUtils::Terminate();
     */
    ~XercesRegistration();

};

#include "NS-CLOSE"
#endif 

tools/xalan/XercesRegistration.cpp

#include "XercesRegistration.h"

#include <xercesc/util/PlatformUtils.hpp>

#include "NS-OPEN"

XercesRegistration::XercesRegistration() {
    using xercesc::XMLPlatformUtils;

    //may throw xercesc::XMLException
    XMLPlatformUtils::Initialize();
}

XercesRegistration::~XercesRegistration() {
    using xercesc::XMLPlatformUtils;

    XMLPlatformUtils::Terminate();
}

#include "NS-CLOSE"

tools/xalan/XalanRegistration.h

#ifndef TOOLS_XALAN_XALANREGISTRATION_H_
#define TOOLS_XALAN_XALANREGISTRATION_H_

#include "tools/xerces/XercesRegistration.h"
#include <xalanc/XalanSourceTree/XalanSourceTreeInit.hpp>

#include "NS-OPEN"

/**
 * \brief XalanRegistration
 *
 * \author David Laštovička
 */
class XalanRegistration {
private:
    typedef xerces::XercesRegistration XercesRegistration;
    typedef xalanc::XalanSourceTreeInit XalanSourceTreeInit;

    //may throw xercesc::XMLException
    XercesRegistration xercesRegistration;

    /**
     * As seen in xalan-c-1.11/c/samples/SimpleXPathAPI/SimpleXPathAPI.cpp
     */
    XalanSourceTreeInit     theSourceTreeInit;

public:

    /**
     * \brief This constructor instantiates the object.
     */
    XalanRegistration();

    ~XalanRegistration();

};

#include "NS-CLOSE"
#endif 

tools/xalan/XalanRegistration.cpp

#include "XalanRegistration.h"

#include <xalanc/XPath/XPathEvaluator.hpp>

#include "NS-OPEN"

XalanRegistration::XalanRegistration() {
    using xalanc::XPathEvaluator;
    XPathEvaluator::initialize();
}

XalanRegistration::~XalanRegistration() {
    using xalanc::XPathEvaluator;
    XPathEvaluator::terminate();
}

#include "NS-CLOSE"

tools/xalan/XmlDoc.h

#ifndef TOOLS_XALAN_XMLDOC_H_
#define TOOLS_XALAN_XMLDOC_H_

#include <memory>
#include <set>
#include "XalanXmlDoc.h"
#include "XmlNode.fwd.h"
#include "tools/exception/EntityNotFound.h"
#include "tools/exception/NotUnique.h"

#include "NS-OPEN"

/**
 * \brief XmlDoc is a simple reader for XML documents.
 *
 * It is meant to be used to:
 * - read only
 * - small documents fitting the memory
 * - fetching data from the document with XPath
 *
 * XmlDoc allows to obtain and pass around a XmlNode representing only
 * a part of the document.
 *
 * XmlDoc/XmlNode can be simply copied or moved around. All their copies
 * internally share one instance of XalanXmlDoc that is released when the last
 * XmlDoc/XmlNode is deleted.
 *
 * \author David Laštovička
 */
class XmlDoc {
private:

    typedef std::string string;
    typedef boost::filesystem::path path;
    template<class T> using Container = std::vector<T>;
    typedef tools::exception::EntityNotFound EntityNotFound;
    typedef tools::exception::NotUnique NotUnique;

    const std::shared_ptr<XalanXmlDoc> xalanXmlDoc;

public:

    /**
     * \brief This constructor instantiates the object.
     */
    XmlDoc(const path &source);

    XmlDoc(const std::shared_ptr<XalanXmlDoc> &xalanXmlDoc);

    XmlDoc(const XmlDoc &) = default;

    XmlDoc(XmlDoc &&) = default;

    XmlNode getRoot() const;

    string getString(const string &xpath) const
    THROW(EntityNotFound);

    Container<string> getStrings(const string &xpath) const;

    std::set<string> getDistinctStrings(const string &xpath) const;

    XmlNode getNode(const string &xpath) const
    THROW(EntityNotFound);

    Container<XmlNode> getNodes(const string &xpath) const;

};

#include "NS-CLOSE"

#endif /* TOOLS_XALAN_XMLDOC_H_ */

tools/xalan/XmlDoc.cpp

#include "XmlDoc.h"

#include "XmlNode.h"

#include "tools/llog/common.h"

#include "NS-OPEN"

XmlDoc::XmlDoc(const path &source)
:   xalanXmlDoc(new XalanXmlDoc(source))
{
}

XmlDoc::XmlDoc(const std::shared_ptr<XalanXmlDoc> &xalanXmlDoc)
:   xalanXmlDoc(xalanXmlDoc)
{

}

auto XmlDoc::getRoot() const
-> XmlNode
{
    return getNode("/");
}

auto XmlDoc::getString(const string &xpath) const
THROW(EntityNotFound)
-> string
{
    //may throw EntityNotFound, NotUnique
    return xalanXmlDoc->getString(xpath);
}

auto XmlDoc::getStrings(const string &xpath) const
-> Container<string>
{
    return xalanXmlDoc->getStrings(xpath);
}

auto XmlDoc::getDistinctStrings(const string &xpath) const
-> std::set<string>
{
    using std::set;
    //ToDo use distinct-values once XPath 2 available in Xalan
    //auto depTypeCodeNodes = xmlDoc.getNodes("distinct-values(/module/dependencies/dependency/@type)");
    auto values = getStrings(xpath);
    set<string> res;
    for (auto value: values)
        res.insert(value);
    return res;
}

auto XmlDoc::getNode(const string &xpath) const
THROW(EntityNotFound)
-> XmlNode
{
    //may throw EntityNotFound, NotUnique
    return XmlNode(xalanXmlDoc,xalanXmlDoc->getNode(xpath));
}

auto XmlDoc::getNodes(const string &xpath) const
-> Container<XmlNode>
{
    using std::transform;
    auto xalanNodes = xalanXmlDoc->getNodes(xpath);
    Container<XmlNode> res;
    transform(
        xalanNodes.begin(), xalanNodes.end(),
        back_inserter(res),
        [this](const XalanXmlDoc::NodeHandle &xalanNode)->XmlNode
        {
            assert(xalanNode);
            return XmlNode(this->xalanXmlDoc,xalanNode);
        }
        );
    return res;
}

#include "NS-CLOSE"

tools/xalan/XmlNode.h

#ifndef TOOLS_XALAN_XMLNODE_H_
#define TOOLS_XALAN_XMLNODE_H_

#include "XalanXmlDoc.h"
#include "XmlDoc.fwd.h"
#include "tools/exception/EntityNotFound.h"
#include "tools/exception/NotUnique.h"

#include "NS-OPEN"

/**
 * \brief XmlDoc
 *
 * \author David Laštovička
 */
class XmlNode {
private:
    typedef std::string string;
    template<class T> using Container = std::vector<T>;
    typedef tools::exception::EntityNotFound EntityNotFound;
    typedef tools::exception::NotUnique NotUnique;

    /**
     * In order to support move assignment and move operator this member
     * is not const
     */
    std::shared_ptr<XalanXmlDoc> xalanXmlDoc;

    /**
     * In order to support (the default) move assignment and move operator
     * implementation this member is not const.
     */
    XalanXmlDoc::NodeHandle node;

public:

    /**
     * Default constructor creates an empty node corresponding to this xml:
     * </>
     */
    XmlNode();

    XmlNode(
        const std::shared_ptr<XalanXmlDoc> &xalanXmlDoc,
        const XalanXmlDoc::NodeHandle &node
        );

    XmlNode(const XmlNode &) = default;

    XmlNode(XmlNode &&) = default;

    XmlDoc getDoc() const;

    string getString(const string &xpath) const
    THROW(EntityNotFound);

    string getString(const string &xpath, const string &defaultValue) const;

    Container<string> getStrings(const string &xpath) const;

    XmlNode getNode(const string &xpath) const
    THROW(EntityNotFound);

    Container<XmlNode> getNodes(const string &xpath) const;

    bool getBool(const string &xpath) const
    THROW(EntityNotFound);

    /**
     * \brief like getBool(xpath) but instead of throwing returns \arg defaultValue
     *
     *
     */
    bool getBool(const string &xpath, bool defaultValue) const;

    string getNodeName() const;

    XmlNode &operator=(const XmlNode &) = default;

    XmlNode &operator=(XmlNode &&) = default;
};

#include "NS-CLOSE"

#endif /* TOOLS_XALAN_XMLNODE_H_ */

tools/xalan/XmlNode.cpp

#include "XmlNode.h"

#include "XmlDoc.h"

#include "tools/llog/common.h"

#include "NS-OPEN"

XmlNode::XmlNode()
:   xalanXmlDoc(new XalanXmlDoc(std::string("<empty/>"))),
    node(xalanXmlDoc->getNode("/"))
{
    assert(this->node);
}

XmlNode::XmlNode(
    const std::shared_ptr<XalanXmlDoc> &xalanXmlDoc,
    const XalanXmlDoc::NodeHandle &node
    )
:   xalanXmlDoc(xalanXmlDoc),
    node(node)
{
    assert(this->node);
}

XmlDoc XmlNode::getDoc() const
{
    return XmlDoc(xalanXmlDoc);
}

auto XmlNode::getString(const string &xpath) const
THROW(EntityNotFound)
-> string
{
    assert(node);
    //may throw EntityNotFound
    return xalanXmlDoc->getString(node,xpath);
}

auto XmlNode::getString(const string &xpath, const string &defaultValue) const
-> string
{
    //may throw EntityNotFound
    return xalanXmlDoc->getString(node,xpath,defaultValue);
}

auto XmlNode::getStrings(const string &xpath) const
-> Container<string>
{
    return xalanXmlDoc->getStrings(node,xpath);
}

auto XmlNode::getNode(const string &xpath) const
THROW(EntityNotFound)
-> XmlNode
{
    BOOST_LOG_FUNCTION();
    //may throw EntityNotFound, NotUnique
    return XmlNode(xalanXmlDoc,xalanXmlDoc->getNode(node,xpath));
}

auto XmlNode::getNodes(const string &xpath) const
-> Container<XmlNode>
{
    using std::transform;
    auto xalanNodes = xalanXmlDoc->getNodes(node,xpath);
    Container<XmlNode> res;
    transform(
        xalanNodes.begin(), xalanNodes.end(),
        back_inserter(res),
        [this](const XalanXmlDoc::NodeHandle &xalanNode)->XmlNode
        {
            return XmlNode(this->xalanXmlDoc,xalanNode);
        }
        );
    return res;
}

auto XmlNode::getBool(const string &xpath) const
THROW(EntityNotFound)
-> bool
{
    //may throw EntityNotFound
    return xalanXmlDoc->getBool(node,xpath);
}

auto XmlNode::getBool(const string &xpath, bool defaultValue) const
-> bool
{
    return xalanXmlDoc->getBool(node,xpath,defaultValue);
}

auto XmlNode::getNodeName() const
-> string
{
    return xalanXmlDoc->getNodeName(node);
}
#include "NS-CLOSE"

XmlDoc.fwd.h

#ifndef TOOLS_XALAN_XMLDOC_FWD_H_
#define TOOLS_XALAN_XMLDOC_FWD_H_

#include "NS-OPEN"

class XmlDoc;

#include "NS-CLOSE"

#endif /* TOOLS_XALAN_XMLDOC_FWD_H_ */

XmlNode.fwd.h

#ifndef TOOLS_XALAN_XMLNODE_FWD_H_
#define TOOLS_XALAN_XMLNODE_FWD_H_

#include "NS-OPEN"

class XmlNode;

#include "NS-CLOSE"

#endif /* TOOLS_XALAN_XMLNODE_FWD_H_ */

XalanXmlDoc.h

#ifndef TOOLS_XALAN_XALANXMLDOC_H_
#define TOOLS_XALAN_XALANXMLDOC_H_

#include <string>
#include <boost/filesystem.hpp>
#include <mutex>
#include <vector>
#include <sstream>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xalanc/XalanDOM/XalanDocument.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeDOMSupport.hpp>
#include <xalanc/XalanSourceTree/XalanSourceTreeParserLiaison.hpp>
#include <xalanc/XPath/XPathEvaluator.hpp>
#include <xalanc/XSLT/XSLTInputSource.hpp>
#include "tools/exception/EntityNotFound.h"
#include "tools/exception/NotUnique.h"

#include "NS-OPEN"

/**
 * \brief XalanXmlDoc
 *
 * This is expected to be used through XmlDoc and XmlNode rather than directly.
 *
 * \see xalan/build/linux-64/xalan-c-1.11/c/samples/XPathWrapper/XPathWrapper.cpp
 *
 * \author David Laštovička
 */
class XalanXmlDoc {
protected:

    typedef std::string string;
    typedef boost::filesystem::path path;
    template<class T> using Container = std::vector<T>;
    typedef xercesc::XercesDOMParser XercesDOMParser;
    typedef xercesc::InputSource InputSource;
    typedef xalanc::XalanDocument XalanDocument;
    typedef xalanc::XalanSourceTreeDOMSupport XalanSourceTreeDOMSupport;
    typedef xalanc::XercesParserLiaison XercesParserLiaison;
    typedef xalanc::XalanSourceTreeParserLiaison XalanSourceTreeParserLiaison;
    typedef xalanc::XalanElement XalanElement;
    typedef xalanc::XalanNode XalanNode;
    typedef std::mutex mutex;
    typedef std::unique_lock<mutex> unique_lock;
    typedef tools::exception::EntityNotFound EntityNotFound;
    typedef tools::exception::NotUnique NotUnique;

public:
    typedef const XalanNode* NodeHandle;
private:

    /**
     * ToDo review Xalan/Xerces behaviour when called concurrently. Maybe the
     * mutex here is not necessary.
     */
    mutex accessMutex;

    mutable XalanSourceTreeDOMSupport domSupport;
    XalanSourceTreeParserLiaison parserLiaison;

    XalanDocument *xalanDoc;

public:

    /**
     * \brief This constructor instantiates the object.
     */
    XalanXmlDoc(const path &sourceFile);

    XalanXmlDoc(const string &xmlString);

    XalanXmlDoc(const XalanXmlDoc &) = delete;

    XalanXmlDoc(XalanXmlDoc &&) = delete;

    ~XalanXmlDoc();

    NodeHandle get_root() const;

    string getString(const string &xpath) const
    THROW(EntityNotFound);

    Container<string> getStrings(const string &xpath) const;

    NodeHandle getNode(const string &xpath) const
    THROW(EntityNotFound);

    Container<NodeHandle> getNodes(const string &xpath) const;

    string getString(const NodeHandle &xalanNode, const string &xpath) const
    THROW(EntityNotFound);

    string getString(const NodeHandle &xalanNode, const string &xpath, const string &defaultValue) const;

    Container<string> getStrings(const NodeHandle &xalanNode, const string &xpath) const;

    NodeHandle getNode(const NodeHandle &xalanNode, const string &xpath) const
    THROW(EntityNotFound);

    Container<NodeHandle> getNodes(
        const NodeHandle &xalanNode, const string &xpath
        ) const;

    /**
     * When more elements do match xpath so the first one is returned.
     * \throw EntityNotFound
     */
    bool getBool(const NodeHandle &xalanNode, const string &xpath) const
    THROW(EntityNotFound);

    /**
     * \brief like getBool(xalanNode, xpath) but instead of throwing EntityNotFound returns \arg defaultValue
     *
     */
    bool getBool(const NodeHandle &xalanNode, const string &xpath, bool defaultValue) const;

    string getNodeName(const NodeHandle &xalanNode) const;

};

#include "NS-CLOSE"

#endif /* TOOLS_XALAN_XALANXMLDOC_H_ */

XalanXmlDoc.cpp

#include "XalanXmlDoc.h"

#include <xercesc/sax/HandlerBase.hpp>
#include <xalanc/XPath/XPathEvaluator.hpp>
#include <xalanc/XPath/NodeRefList.hpp>
#include <xalanc/XalanDOM/XalanElement.hpp>
#include <xalanc/XalanDOM/XalanNamedNodeMap.hpp>
#include "tools/llog/common.h"
#include <sstream>
#include <vector>
#include "tools/text/ostream_iterator.h"
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include "tools/exception/Other.h"
#include "tools/exception/util/backtraceFactory.obj.h"
#include <xalanc/DOMSupport/XalanDocumentPrefixResolver.hpp>

#include "NS-OPEN"

static std::string toString(const xalanc::XalanDOMString &val)
{
    return std::string(val.begin(), val.end());
}

static void outputAttrs(std::ostream &oss, xalanc::XalanNode const * const node)
{
    using std::ostringstream;
    using xalanc::XalanNode;
    using xalanc::XalanElement;
    using xalanc::XalanSize_t;
    if (node->getNodeType()==XalanNode::ELEMENT_NODE) {
        XalanElement const * const element = static_cast<XalanElement const * const>(node);
        oss << "[";
        for (XalanSize_t i = 0; i<element->getAttributes()->getLength(); i++) {
            if (i>0) oss << ' ';
            oss << '@' << toString(element->getAttributes()->item(i)->getNodeName())
                << "='"
                << toString(element->getAttributes()->item(i)->getNodeValue())
                << "'";
        }
        oss << "]";
    }
}

static void outputFullPathWithAttrs(
    std::ostream &oss,
    xalanc::XalanNode const * const node,
    bool outputAttrsRequested
    )
{
    using std::ostringstream;
    using std::string;
    using std::vector;
    using tools::text::ostream_iterator;
    using std::copy;
    using xalanc::XalanNode;

    vector<string> nodeNames;
    {
        for(XalanNode const *it = node; it!=nullptr; it=it->getParentNode())
        {
            ostringstream oss;
            oss << toString(it->getNodeName());
            if (outputAttrsRequested)
                outputAttrs(oss, it);
            nodeNames.push_back(oss.str());
        }
    }

    copy(
        nodeNames.rbegin(), nodeNames.rend(),
        ostream_iterator<string>(oss,nullptr,nullptr,"/")
        );

}
/*
static std::string createFullPath(xalanc::XalanNode const * const node)
{
    using std::ostringstream;
    ostringstream oss;
    outputFullPathWithAttrs(oss,node,false);
    return oss.str();
}
*/
static std::string createFullPathWithAttrs(xalanc::XalanNode const * const node)
{
    using std::ostringstream;
    ostringstream oss;
    outputFullPathWithAttrs(oss,node,true);
    return oss.str();
}

XalanXmlDoc::XalanXmlDoc(const path &source)
:   //domSupport(parserLiaison),
    parserLiaison(domSupport)
{
    using xercesc::LocalFileInputSource;
    using xalanc::XalanDOMString;
    domSupport.setParserLiaison(&parserLiaison);
    const XalanDOMString    theFileName(source.native().c_str());
    LocalFileInputSource theInputSource(theFileName.c_str());
    xalanDoc = parserLiaison.parseXMLStream(theInputSource);
}

XalanXmlDoc::XalanXmlDoc(const string &xmlString)
:   //domSupport(parserLiaison),
    parserLiaison(domSupport)
{
    using xercesc::MemBufInputSource;
    using xalanc::XalanDOMString;
    domSupport.setParserLiaison(&parserLiaison);
    MemBufInputSource theInputSource(
        (const XMLByte *)xmlString.c_str(),
        xmlString.size(),
        "XalanXmlDoc"
        );
    xalanDoc = parserLiaison.parseXMLStream(theInputSource);
}

XalanXmlDoc::~XalanXmlDoc()
{
}

auto XalanXmlDoc::get_root() const
-> NodeHandle
{
    return xalanDoc;
}

auto XalanXmlDoc::getString(const string &xpath) const
THROW(EntityNotFound)
-> string
{
    //may throw EntityNotFound, NotUnique
    return getString(get_root(),xpath);
}

auto XalanXmlDoc::getStrings(const string &xpath) const
-> Container<string>
{
    return getStrings(get_root(),xpath);
}

auto XalanXmlDoc::getNode(const string &xpath) const
THROW(EntityNotFound)
-> NodeHandle
{
    //may throw EntityNotFound, NotUnique
    return getNode(get_root(), xpath);
}

auto XalanXmlDoc::getNodes(const string &xpath) const
-> Container<NodeHandle>
{
    return getNodes(get_root(), xpath);
}

auto XalanXmlDoc::getString(const NodeHandle &xalanNode, const string &xpath) const
THROW(EntityNotFound)
-> string
{
    //may throw EntityNotFound, NotUnique
    auto found = getNode(xalanNode, xpath);

    return toString(found->getNodeValue());
}

auto XalanXmlDoc::getString(const NodeHandle &xalanNode, const string &xpath, const string &defaultValue) const
-> string
{
    using exception::EntityNotFound;

    string res;
    try {
        //may throw EntityNotFound
        auto found = getNode(xalanNode, xpath);
        res = toString(found->getNodeValue());
    } catch (const EntityNotFound &e) {
        res = defaultValue;
    }
    return res;
}

auto XalanXmlDoc::getStrings(const NodeHandle &xalanNode, const string &xpath) const
-> Container<string>
{
    Container<string> res;
    for (auto node: getNodes(xalanNode, xpath))
    {
        res.push_back(toString(node->getNodeValue()));
    }
    return res;
}

auto XalanXmlDoc::getNode(const NodeHandle &xalanNode, const string &xpath) const
THROW(EntityNotFound)
-> NodeHandle
{
    BOOST_LOG_FUNCTION();

    using xalanc::XalanNode;
    using xalanc::XalanDOMString;
    using xalanc::XPathEvaluator;
    using std::ostringstream;
    using xercesc::SAXParseException;
    using xalanc::XalanDocumentPrefixResolver;

#ifndef NDEBUG
    if (!xalanNode) {
        BOOST_LOG_TRIVIAL(trace)
            << "Assertion failed evaluating " << xpath;
        BOOST_LOG_TRIVIAL(trace)
            << tools::exception::util::backtraceFactory().createBacktraces();
    }
    assert(xalanNode);

    {
        std::ostringstream oss;
        outputFullPathWithAttrs(oss,xalanNode,true);
        BOOST_LOG_TRIVIAL(trace)
            << "XalanXmlDoc::getNode " << xpath << " on type "
            << xalanNode->getNodeType()
            << " in " << oss.str();
    }
#endif
    //ToDo try can be removed the SAXParseException probably not thrown here but in the constructor
    try {
        XalanDocumentPrefixResolver thePrefixResolver(xalanDoc);
        const XalanDOMString expression(xpath.c_str());
        BOOST_LOG_TRIVIAL(trace) << "expression prepared";
        XPathEvaluator evaluator;

        //better use mutex when accessing the global domSupport etc.
        unique_lock(accessMutex);
        const XalanNode* found = evaluator.selectSingleNode(
            domSupport,
            const_cast<XalanNode *>(xalanNode),
            expression.c_str(),
            thePrefixResolver
            );

        if (!found) {
            ostringstream oss;
            oss << "Not found " << xpath << " on the node " << createFullPathWithAttrs(xalanNode);
            throw EntityNotFound(SRCINF, oss.str());
        }
        assert(found);
        BOOST_LOG_TRIVIAL(trace) << "returning node";
        return found;
    } catch (const SAXParseException &e) {
        using std::ostringstream;
        using exception::Other;
        ostringstream oss;
        oss << "SAXParseException line: " << e.getLineNumber() << " column: "
            << e.getColumnNumber() << " message: " << e.getMessage();
        throw Other(SRCINF,oss.str());
    }
}

auto XalanXmlDoc::getNodes(const NodeHandle &xalanNode, const string &xpath) const
-> Container<NodeHandle>
{
    using xalanc::XalanNode;
    using xalanc::XalanDOMString;
    using xalanc::XPathEvaluator;
    using xalanc::NodeRefList;
    using xercesc::SAXParseException;
    using xalanc::XalanDocumentPrefixResolver;

    BOOST_LOG_TRIVIAL(trace)
        << "XalanXmlDoc::getNodes " << xpath;

    //ToDo try can be removed the SAXParseException probably not thrown here but in the constructor
    try {
        XalanDocumentPrefixResolver thePrefixResolver(xalanDoc);
        const XalanDOMString expression(xpath.c_str());

        XPathEvaluator evaluator;

        NodeRefList foundNodes;

        {
            //better use mutex when accessing the global domSupport etc.
            unique_lock(accessMutex);

            evaluator.selectNodeList(
                foundNodes,
                domSupport,
                const_cast<XalanNode *>(xalanNode),
                expression.c_str(),
                thePrefixResolver
                );
        }
        std::vector<const XalanNode*> res;
        for (NodeRefList::size_type i=0;i<foundNodes.getLength();i++) {
            assert(foundNodes.item(i));
            res.push_back(foundNodes.item(i));
        }
        return res;
    } catch (const SAXParseException &e) {
        using std::ostringstream;
        using exception::Other;
        ostringstream oss;
        oss << "SAXParseException line: " << e.getLineNumber() << " column: "
            << e.getColumnNumber() << " message: " << e.getMessage();
        throw Other(SRCINF,oss.str());
    }
}
auto XalanXmlDoc::getBool(const NodeHandle &xalanNode, const string &xpath) const
THROW(EntityNotFound)
-> bool
{
    bool res;
    //may throw EntityNotFound, NotUnique
    std::istringstream(getString(xalanNode,xpath)) >> std::boolalpha >> res;
    return res;
}

auto XalanXmlDoc::getBool(const NodeHandle &xalanNode, const string &xpath, bool defaultValue) const
-> bool
{
    using exception::EntityNotFound;
    bool res;
    try {
        //may throw EntityNotFound, NotUnique
        res = getBool(xalanNode,xpath);
    } catch (const EntityNotFound &e) {
        res = defaultValue;
    }
    return res;
}

auto XalanXmlDoc::getNodeName(const NodeHandle &xalanNode) const
-> string
{
    assert(xalanNode);
    return toString(xalanNode->getNodeName());
}

#include "NS-CLOSE"