栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++11 boost::spirit::qi简单的XML解析器示例

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++11 boost::spirit::qi简单的XML解析器示例

boost::spirit::qi是一个简单的解释器开发库。可以用来解析文本,构建解释器等。
笔者花了两天时间看完了README文档,并且照着Demo代码写了一遍。感觉语法很复杂。特别是最后的一个XML解析器,很容易就写错了。好在错误信息还是很好理解的。
现在把代码贴出来和大家共享一下。
代码结构如下,

test/CMakeLists.txt

cmake_minimum_required(VERSION 2.6)

if(APPLE)
    message(STATUS "This is Apple, do nothing.")
    set(CMAKE_MACOSX_RPATH 1)
    set(CMAKE_PREFIX_PATH /Users/aabjfzhu/software/vcpkg/ports/cppwork/vcpkg_installed/x64-osx/share )
elseif(UNIX)
    message(STATUS "This is linux, set CMAKE_PREFIX_PATH.")
    set(CMAKE_PREFIX_PATH /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/share)
endif(APPLE)

project(spirit_xml_error_handling)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing")

add_definitions(-g)

find_package(ZLIB)

find_package(OpenCV REQUIRED )
find_package(Arrow CONFIG REQUIRED)

find_package(unofficial-brotli REQUIRED)
find_package(unofficial-utf8proc CONFIG REQUIRED)
find_package(Thrift CONFIG REQUIRED)

find_package(glog REQUIRED)

find_package(OpenSSL REQUIRED)

find_package(Boost REQUIRED COMPONENTS
    system
    filesystem
    serialization
    program_options
    thread
    )

find_package(DataFrame REQUIRED)

if(APPLE)
    MESSAGE(STATUS "This is APPLE, set INCLUDE_DIRS")
set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include /usr/local/iODBC/include /opt/snowflake/snowflakeodbc/include/ ${CMAKE_CURRENT_SOURCE_DIR}/../include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
elseif(UNIX)
    MESSAGE(STATUS "This is linux, set INCLUDE_DIRS")
    set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include ${CMAKE_CURRENT_SOURCE_DIR}/../include/   ${CMAKE_CURRENT_SOURCE_DIR}/../../../include/)
endif(APPLE)


if(APPLE)
    MESSAGE(STATUS "This is APPLE, set LINK_DIRS")
    set(LINK_DIRS /usr/local/lib /usr/local/iODBC/lib /opt/snowflake/snowflakeodbc/lib/universal)
elseif(UNIX)
    MESSAGE(STATUS "This is linux, set LINK_DIRS")
    set(LINK_DIRS ${Boost_INCLUDE_DIRS} /usr/local/lib /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/lib)
endif(APPLE)

if(APPLE)
    MESSAGE(STATUS "This is APPLE, set ODBC_LIBS")
    set(ODBC_LIBS iodbc iodbcinst)
elseif(UNIX)
    MESSAGE(STATUS "This is linux, set LINK_DIRS")
    set(ODBC_LIBS odbc odbcinst ltdl)
endif(APPLE)

include_directories(${INCLUDE_DIRS})
LINK_DIRECTORIES(${LINK_DIRS})

file( GLOB test_file_list ${CMAKE_CURRENT_SOURCE_DIR}
struct mini_xml;

// 要么是 mini_xml的递归结构,要么是std::string
// 这个节点的两种属性
using mini_xml_node =
    boost::variant, std::string>;

struct mini_xml {
    std::string name;                     // Tag name
    std::vector children;  // children
};
};  // namespace client

BOOST_FUSION_ADAPT_STRUCT(client::mini_xml,
                          (std::string,
                           name)(std::vector, children))

namespace client {
// print out the mini xml tree
int const tabsize = 4;

void tab(int indent) {
    for (int i = 0; i < indent; ++i) {
        std::cout << ' ';
    }
}

struct mini_xml_printer {
    mini_xml_printer(int indent_ = 0) : indent{indent_} {}

    void operator()(mini_xml const& xml) const;
    int indent;
};

struct mini_xml_node_printer : boost::static_visitor<> {
    mini_xml_node_printer(int indent_ = 0) : indent{indent_} {}

    void operator()(mini_xml const& xml) const {
        mini_xml_printer(indent + tabsize)(xml);
    }

    void operator()(std::string const& text) const {
        tab(indent + tabsize);
        std::cout << "text: "" << text << '"' << std::endl;
    }
    int indent;
};

void mini_xml_printer::operator()(mini_xml const& xml) const {
    tab(indent);
    std::cout << "tag: " << xml.name << std::endl;
    tab(indent);

    std::cout << '{' << std::endl;
    for (auto&& node : xml.children) {
        boost::apply_visitor(mini_xml_node_printer(indent), node);
    }
    tab(indent);
    std::cout << '}' << std::endl;
}

// 使用本地变量保存中间临时值, qi::locals
// Refers to: https://www.boost.org/doc/libs/1_66_0/libs/spirit/doc/html/spirit/qi/tutorials/mini_xml___error_handling.html
// Our mini xml grammar definition
template 
struct mini_xml_grammar : qi::grammar, ascii::space_type> {

    
    mini_xml_grammar() : mini_xml_grammar::base_type(xml, "xml_grammar") {
        using ascii::char_;
        using ascii::string;
        using qi::on_error;
        using qi::fail;
        using qi::lexeme;
        using qi::lit;
        using namespace qi::labels;

        using phoenix::at_c;
        using phoenix::push_back;
        using phoenix::val;
        using phoenix::construct;

        text %= lexeme[+(char_ - '<')];
        node %= (xml | text);
        start_tag %=
            '<' >> !lit('/') >> lexeme[+(char_ - '>')] >> '>';

        // r1表示继承 start_tag中的属性
        end_tag = "> string(_r1) >> '>';

        // 复用start_tag的内容是通过 这里实现的
        // 这里其实实现的是一个boost::fusion::tuple
        // 0 = start_tag content
        // ..... 若干 nodes
        // 最后验证end_tag == start_tag,但是不push_back
        xml %= start_tag[_a = _1] >>
              *node >> end_tag(_a);

        // 给各个rule命名
        xml.name("xml");
        node.name("node");
        text.name("text");
        start_tag.name("start_tag");
        end_tag.name("end_tag");

        on_error(
            xml, 
            std::cout << 
                val("Error! Expecting ")
                << _4   // What failed
                << val(" here"")
                << construct(_3, _2) // Iterators to error-pos, end
                << val(""")
                << std::endl
        ); 
    }
    qi::rule text;
    qi::rule node;
    qi::rule start_tag;
    // 继承属性,需要验证start_tag中的字符串
    qi::rule end_tag;
    qi::rule, ascii::space_type> xml;
};
};  // namespace client

#endif

test/data/1.xml


Tove
Jani
Reminder
Don't forget me this weekend!

test/data/2.xml


程序输出如下,

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/873371.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号