[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/nlitsme/cpputils/master/include/cpputils/xmlparser.h [Back]  [Original]

#pragma once
#include 
#include 
#include 
#include 
#include 
#include 

// TODO: add optional support for non-quoted attribute values, and attributes without a value, so i can parse most html too.
// TODO: support the nested   type values.

// TODO: add method for searching attribute_list
/*
 * XmlParser based upon how the python 'html.parser' works.
 */
class XmlParser {
    //        - processing instructions
    //   handler
    //     handler
    //    handler
    //      handler
    //   handler
    //    handler
    //  ... data handler
    //  &entity;
public:
    using attribute_list = std::vector;

    virtual ~XmlParser()  { }

    // implement these methods when subclassing this parser
    virtual void handle_starttag(std::string tag, const attribute_list& attrs) { }
    virtual void handle_endtag(std::string tag) { }
    virtual void handle_element(std::string tag, const attribute_list& attrs)
    {
        handle_starttag(tag, attrs);
        handle_endtag(tag);
    }
    virtual void handle_xml_decl(std::string tag, const attribute_list& attrs) { }
    virtual void handle_comment(const char*first, const char*last) { }
    virtual void handle_data(const char*first, const char*last) { }

    enum {
        TOKEN_LESS_THEN,
        TOKEN_LT_QUESTION,
        TOKEN_LT_EXCLAMATION,
        TOKEN_LT_SLASH,
        //TOKEN_GREATER_THEN,
        //TOKEN_QUESTION_GT,
        //TOKEN_SLASH_GT,
        TOKEN_NAME,
        TOKEN_STRING,
        TOKEN_EQUALS,
        // note: no token for comment, cdata
    };
    struct Token {
        virtual ~Token() { }
        virtual int type() = 0;
        virtual std::string name() const { return {}; }
        virtual std::string value() const { return {}; }
    };
    struct LT_Token : Token {
        int type() override { return TOKEN_LESS_THEN; }
    };
    struct LTQ_Token : Token {
        int type() override { return TOKEN_LT_QUESTION; }
    };
    struct LTX_Token : Token {
        int type() override { return TOKEN_LT_EXCLAMATION; }
    };
    struct LTS_Token : Token {
        int type() override { return TOKEN_LT_SLASH; }
    };

//  struct GT_Token : Token {
//      int type() override { return TOKEN_GREATER_THEN; }
//  };
//  struct SGT_Token : Token {
//      int type() override { return TOKEN_SLASH_GT; }
//  };
//  struct QGT_Token : Token {
//      int type() override { return TOKEN_QUESTION_GT; }
//  };
    struct NAME_Token : Token {
        const char *first;
        const char *last;

        NAME_Token(const char *first, const char *last)
            : first(first), last(last)
        {
        }

        int type() override { return TOKEN_NAME; }

        std::string name() const override { return {first, last}; }
    };
    struct STRING_Token : Token {
        const char *first;
        const char *last;

        STRING_Token(const char *first, const char *last)
            : first(first), last(last)
        {
        }

        int type() override { return TOKEN_STRING; }

        std::string value() const override { return {first, last}; }
    };
    struct EQ_Token : Token {
        int type() override { return TOKEN_EQUALS; }
    };

private:
    std::vector _stack;
public:
    template
    static std::string decode_entities(const STR& str)
    {
        // TODO  - decode entities
        return str;
    }
    template
    static std::string encode_entities(const STR& str)
    {
        // TODO  - encode entities
        return str;
    }

    int stack_find(int token)
    {
        int i = _stack.size()-1;
        while (i>=0) {
            if (_stack[i]->type() == token)
                return i;
        }
        return -1;
    }
    template
    bool stack_match(int token, ARGS...args)
    {
        if (_stack.size() < 1 + sizeof...(ARGS))
            return false;
        if (_stack[_stack.size()-1-sizeof...(ARGS)]->type() != token)
            return false;

        if constexpr (sizeof...(ARGS) != 0)
            return stack_match(args...);
        else
            return true;
    }
    auto stack_pop_attr()
    {
        attribute_list attrs;
        while (stack_match(TOKEN_NAME, TOKEN_EQUALS, TOKEN_STRING)) {
            auto value = _stack.back();
            _stack.pop_back();
            _stack.pop_back(); // '='
            auto name = _stack.back();
            _stack.pop_back();

            attrs.emplace_back(std::string(name->name()), decode_entities(value->value()));
        }
        std::reverse(attrs.begin(), attrs.end());
        return attrs;
    }

    // NOTE: this needs to be a templated function, otherwise the
    // if-constexpr will not eliminate the always-true comparisons.
    template
    static bool isnamechar(CHAR c)
    {
        if constexpr (std::is_signed_v) {
            if (c < 0) return true;
        }
        if (c 
                    ++q;
                    auto attrs = stack_pop_attr();
                    if (!stack_match(TOKEN_LT_QUESTION, TOKEN_NAME))
                        throw std::runtime_error("invalid xml#6");
                    auto tagname = _stack.back();
                    _stack.pop_back();
                    _stack.pop_back();  // '

Web Proxy Viewer  |  New URL  |  Original Page