diff --git a/iguana/xml_reader.hpp b/iguana/xml_reader.hpp index 15634134..829a2705 100644 --- a/iguana/xml_reader.hpp +++ b/iguana/xml_reader.hpp @@ -118,17 +118,8 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end, match<'<'>(it, end); if (*it == '?' || *it == '!') IGUANA_UNLIKELY { - // skip '>(it, end); - ++it; - skip_sapces_and_newline(it, end); - continue; - } + --it; + return; } auto start = it; skip_till_greater_or_space(it, end); @@ -220,27 +211,48 @@ IGUANA_INLINE void skip_object_value(It &&it, It &&end, std::string_view name) { throw std::runtime_error("unclosed tag: " + std::string(name)); } +// skip +template +IGUANA_INLINE void skip_instructions(It &&it, It &&end) { + while (*(it - 1) != '?') { + ++it; + skip_till<'>'>(it, end); + } + ++it; +} + +template +IGUANA_INLINE void skip_cdata(It &&it, It &&end) { + ++it; + skip_till<']'>(it, end); + ++it; + match<']', '>'>(it, end); +} + +template +IGUANA_INLINE void skip_comment(It &&it, It &&end) { + while (*(it - 1) != '-' || *(it - 2) != '-') { + ++it; + skip_till<'>'>(it, end); + } + ++it; +} + // return true means reach the close tag template , int> = 0> -IGUANA_INLINE auto skip_till_key(T &value, It &&it, It &&end) { - skip_sapces_and_newline(it, end); +IGUANA_INLINE auto skip_till_close_tag(T &value, It &&it, It &&end) { while (true) { + skip_sapces_and_newline(it, end); match<'<'>(it, end); if (*it == '/') IGUANA_UNLIKELY { - // - return true; // reach the close tag + // reach the close tag + return true; } else if (*it == '?') IGUANA_UNLIKELY { - // - while (*(it - 1) != '?') { - ++it; - skip_till<'>'>(it, end); - } - ++it; - skip_sapces_and_newline(it, end); + skip_instructions(it, end); continue; } else if (*it == '!') @@ -249,12 +261,7 @@ IGUANA_INLINE auto skip_till_key(T &value, It &&it, It &&end) { if (*it == '[') { // >()) { - ++it; - skip_till<']'>(it, end); - ++it; - match<']', '>'>(it, end); - skip_sapces_and_newline(it, end); - continue; + skip_cdata(it, end); } else { // if parse cdata @@ -274,32 +281,53 @@ IGUANA_INLINE auto skip_till_key(T &value, It &&it, It &&end) { &*vb, static_cast(std::distance(vb, ve))); } match<']', '>'>(it, end); - skip_sapces_and_newline(it, end); - continue; } } else if (*it == '-') { // - while (*(it - 1) != '-' || *(it - 2) != '-') { - ++it; - skip_till<'>'>(it, end); - } - ++it; - skip_sapces_and_newline(it, end); - continue; + skip_comment(it, end); } else { - // skip_till<'>'>(it, end); ++it; - skip_sapces_and_newline(it, end); - continue; } + continue; } return false; } } +template +IGUANA_INLINE void skip_till_first_key(It &&it, It &&end) { + while (it != end) { + skip_sapces_and_newline(it, end); + match<'<'>(it, end); + if (*it == '?') + IGUANA_UNLIKELY { + skip_instructions(it, end); + continue; + } + else if (*it == '!') + IGUANA_UNLIKELY { + ++it; + if (*it == '-') { + // + skip_comment(it, end); + } + else { + // + skip_till<'>'>(it, end); + ++it; + } + continue; + } + else { + break; + } + } +} + template IGUANA_INLINE void check_required(std::string_view key_set) { if constexpr (iguana::has_iguana_required_arr_v) { @@ -322,7 +350,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, constexpr auto cdata_idx = get_type_index(); skip_till<'>'>(it, end); ++it; - if (skip_till_key(value, it, end)) { + if (skip_till_close_tag(value, it, end)) { match_close_tag(it, end, name); return; } @@ -353,7 +381,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, key_set.append(key).append(", "); } } - if (skip_till_key(value, it, end)) + if (skip_till_close_tag(value, it, end)) IGUANA_UNLIKELY { match_close_tag(it, end, name); parse_done = true; @@ -398,7 +426,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, skip_object_value(it, end, key); #endif } - if (skip_till_key(value, it, end)) { + if (skip_till_close_tag(value, it, end)) { match_close_tag(it, end, name); check_required(key_set); return; @@ -414,17 +442,7 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end, template , int> = 0> IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { - while (it != end) { - skip_sapces_and_newline(it, end); - match<'<'>(it, end); - if (*it == '?') { - skip_till<'>'>(it, end); - ++it; - } - else { - break; - } - } + detail::skip_till_first_key(it, end); auto start = it; skip_till_greater_or_space(it, end); std::string_view key = @@ -435,17 +453,7 @@ IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { template , int> = 0> IGUANA_INLINE void from_xml(U &value, It &&it, It &&end) { - while (it != end) { - skip_sapces_and_newline(it, end); - match<'<'>(it, end); - if (*it == '?') { - skip_till<'>'>(it, end); - ++it; // skip > - } - else { - break; - } - } + detail::skip_till_first_key(it, end); auto start = it; skip_till_greater_or_space(it, end); std::string_view key = diff --git a/test/test_xml.cpp b/test/test_xml.cpp index 0ec90d88..a7796bc9 100644 --- a/test/test_xml.cpp +++ b/test/test_xml.cpp @@ -470,6 +470,7 @@ TEST_CASE("test province example") { CHECK(p.cities->city[1].area.value() == 20788); }; std::string str = R"( + Chengdu ]]> @@ -485,6 +486,7 @@ TEST_CASE("test province example") { ]]> 20788 +