【问题标题】:Xalan-c++: returning a node with XPath (reference to local pointer)Xalan-c++:返回带有 XPath 的节点(对本地指针的引用)
【发布时间】:2013-12-11 09:06:08
【问题描述】:

我是 Xalan 和 Xerces 的新手,我尝试通过 XPath 选择一个特定节点。应该可以通过引用返回 xml 数据,但也需要更改 - 这就是为什么我将它保存为 DOMDocument 以便能够通过 xerces 访问数据来操作它们。我有两种方法,一种是读取 xml 文件并进行模式验证,另一种是获取特定节点。我正在使用 Visual Studio 2012,当然还有 Xalan 和 Xerces 库。我尝试创建一个 SSCCE 来向您展示我的问题:

头文件:

#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,我无法将其创建为全局变量,因为我收到默认构造函数是私有的错误消息。

所以我希望你们中的任何人都可以给我一些建议。

【问题讨论】:

    标签: c++ xml xpath xerces xalan


    【解决方案1】:

    您不能只保留 XalanNode * 而忘记所有其他内容。如果您想在您的应用程序中传递 XmlNode,您必须将其封装到您自己的类中,该类将在内部保存 XalanNode * 所需的所有内容。

    为了证明这一点,我将附上一些我在项目中使用的辅助文件。这些文件将“按原样”粘贴,即您可能会在编译它们时遇到一些困难,因为它们是更大项目的一部分并且有一些我将省略的依赖项(如 boost 日志记录、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,以便可以轻松地在应用程序中传递文档或节点。

    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 
    

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 2021-11-30
      相关资源
      最近更新 更多