2013-12-11 37 views
3

我是Xalan和Xerces的新手,我嘗試通過XPath選擇一個特定的節點。應該可以通過引用返回xml數據,但也需要更改 - 這就是爲什麼我將它保存爲DOMDocument以便能夠通過xerces訪問數據來操作它們。我有兩種方法來讀取一個XML文件,並做架構驗證和一個獲取特定的節點。我正在使用Visual Studio 2012,當然還有Xalan和Xerces庫。我試圖創建一個SSCCE向你展示我的問題:Xalan-C++:使用XPath返回一個節點(引用到本地指針)

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

源文件:

#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; 
    } 
} 

,我的主要功能:

#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; 
} 

的問題是我需要通過引用返回節點的所有屬性。但問題是,點頭只是一個局部指針,如果他超出範圍,那麼它是無效的。 我已經嘗試將它保存爲成員變量,但指針的所有權屬於XercesDOMWrapperParsedSource,我無法將其作爲全局變量創建,因爲我收到默認構造函數爲私有的錯誤消息。

所以我希望你們任何人都能給我一些建議。

回答

0

你不能只保留XalanNode *而忘記其餘的一切。如果你想在你的應用程序周圍傳遞XmlNode,你必須將它封裝到你自己的類中,它將在內部保存XalanNode *所需的所有內容。

爲了證明這一點,我將附加一些在我的項目中使用的輔助文件。這些文件將被「按原樣」粘貼,也就是說,你可能會因爲它們是一個更大的項目的一部分而苦苦掙扎,因爲它們是一個更大的項目的一部分,並且有一些我將省略的依賴項(例如boost logging,boost :: filesystem :: path ;你可以輕鬆擺脫這些依賴)。然而,如果有人需要它,所以我相信他們將很容易適應您的項目並理解這個想法。

提供的類用於將xml文檔加載到內存中,並允許使用XPath表達式讀取它。

這裏是我的類的使用的一個例子。

#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) { 
     ... 
    } 
} 

這裏去包括類(抱歉,如果這不是附加在這個網站更大的東西最好的方法)

主要實現在XalanXmlDoc保存所有的背景之下,是不可拷貝。 XmlDoc和XmlNode方便地包裝XalanXmlDoc,以便文檔或節點可以輕鬆地在應用程序中傳遞。

工具/ 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 

工具/ 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" 

工具/ 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 

工具/ 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" 

工具/ 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_ */ 

工具/ 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" 

工具/ 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"