diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml
index e3be5eb1..078402ae 100644
--- a/.github/workflows/clang-format.yml
+++ b/.github/workflows/clang-format.yml
@@ -2,9 +2,9 @@ name: Clang Format Diff
on:
push:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
pull_request:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
jobs:
build:
diff --git a/.github/workflows/linux-clang.yml b/.github/workflows/linux-clang.yml
index e2e7f01c..401c8570 100644
--- a/.github/workflows/linux-clang.yml
+++ b/.github/workflows/linux-clang.yml
@@ -2,9 +2,9 @@ name: Ubuntu (clang)
on:
push:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
pull_request:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
jobs:
build:
diff --git a/.github/workflows/linux-gcc.yml b/.github/workflows/linux-gcc.yml
index caaba1ef..1e0596f8 100644
--- a/.github/workflows/linux-gcc.yml
+++ b/.github/workflows/linux-gcc.yml
@@ -2,9 +2,9 @@ name: Ubuntu (gcc)
on:
push:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
pull_request:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
jobs:
build:
diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml
index 035f72de..c334ff00 100644
--- a/.github/workflows/mac.yml
+++ b/.github/workflows/mac.yml
@@ -2,9 +2,9 @@ name: macOS Monterey 12
on:
push:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
pull_request:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
jobs:
build:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index a93d8f62..6a9583d8 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -2,9 +2,9 @@ name: Windows Server 2022
on:
push:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
pull_request:
- branches: [ master, fullsupport_xml]
+ branches: [ master, improve_xml]
jobs:
build:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3822a92c..b463ae1b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -53,6 +53,7 @@ set(TEST_YAML test/test_yaml.cpp test/test_yaml_bech.cpp)
set(YAMLBENCH benchmark/yaml_benchmark.cpp)
set(TEST_NOTHROW test/test_yaml_nothrow.cpp)
set(TEST_UTIL test/test_util.cpp)
+set(TEST_XMLNOTHROW test/test_xml_nothrow.cpp)
add_executable(json_example ${JSON_EXAMPLE})
add_executable(xml_example ${XML_EXAMPLE})
@@ -67,6 +68,7 @@ add_executable(test_yaml ${TEST_YAML})
add_executable(yaml_benchmark ${YAMLBENCH})
add_executable(test_nothrow ${TEST_NOTHROW})
add_executable(test_util ${TEST_UTIL})
+add_executable(test_xml_nothrow ${TEST_XMLNOTHROW})
# unit test
option(BUILD_UNIT_TESTS "Build unit tests" ON)
@@ -91,3 +93,4 @@ add_test(NAME test_xml COMMAND test_xml)
add_test(NAME test_yaml COMMAND test_yaml)
add_test(NAME test_nothrow COMMAND test_nothrow)
add_test(NAME test_util COMMAND test_util)
+add_test(NAME test_xml_nothrow COMMAND test_xml_nothrow)
diff --git a/README.md b/README.md
index e80960b1..7b3cd433 100644
--- a/README.md
+++ b/README.md
@@ -96,14 +96,10 @@ person p = {"admin", 20};
iguana::string_stream ss; // here use std::string is also ok
iguana::to_xml(ss, p);
std::cout << ss.str() << std::endl;
-// you can also call iguana::to_xml_pretty to get pretty string
-iguana::string_stream s;
-iguana::to_xml_pretty(s, p);
-std::cout << s.str() << std::endl;
// deserialization the structure from the string
std::string xml = " buke 30";
-iguana::from_xml(p, xml.data());
+iguana::from_xml(p, xml);
```
#### Serialization of yaml
@@ -212,7 +208,7 @@ std::string str = R"(
)";
library_t lib;
-iguana::from_xml(lib, str.data());
+iguana::from_xml(lib, str);
```
#### yaml
diff --git a/iguana/json_writer.hpp b/iguana/json_writer.hpp
index 7dd5c770..4134f4f8 100644
--- a/iguana/json_writer.hpp
+++ b/iguana/json_writer.hpp
@@ -174,12 +174,12 @@ template
IGUANA_INLINE void render_json_value(Stream &s, T &&t) {
using U = typename std::decay_t;
s.push_back('[');
- const size_t size = std::tuple_size_v;
+ constexpr size_t size = std::tuple_size_v;
for_each(std::forward(t),
[&s, size](auto &v, auto i) IGUANA__INLINE_LAMBDA {
render_json_value(s, v);
- if (i != size - 1)
+ if (i != size - 1) [[likely]]
s.push_back(',');
});
s.push_back(']');
diff --git a/iguana/xml_reader.hpp b/iguana/xml_reader.hpp
index 53488d52..0f8b1384 100644
--- a/iguana/xml_reader.hpp
+++ b/iguana/xml_reader.hpp
@@ -159,6 +159,30 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end,
parse_item(value.value(), it, end, name);
}
+// /> or skip >、 and until the
+// loose inspection here
+template
+IGUANA_INLINE void skip_object_value(It &&it, It &&end, std::string_view name) {
+ skip_till_greater(it, end);
+ ++it;
+ if (*(it - 2) == '/') {
+ // .../>
+ return;
+ }
+ //
+ size_t size = name.size();
+ while (it != end) {
+ skip_till_greater(it, end);
+ if (*(it - size - 2) == '<' && *(it - size - 1) == '/' &&
+ (std::string_view{&*(it - size), size} == name)) {
+ ++it;
+ return;
+ }
+ ++it;
+ }
+ throw std::runtime_error("unclosed tag: " + std::string(name));
+}
+
template
IGUANA_INLINE void parse_item(T &value, It &&it, It &&end,
std::string_view name) {
@@ -241,12 +265,16 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end,
"type must be memberptr");
using V = std::remove_reference_t;
if constexpr (!cdata_t) {
- detail::parse_item(value.*member_ptr, it, end, key);
+ parse_item(value.*member_ptr, it, end, key);
}
},
member_it->second);
} else [[unlikely]] {
+#ifdef THROW_UNKNOWN_KEY
throw std::runtime_error("Unknown key: " + std::string(key));
+#else
+ skip_object_value(it, end, key);
+#endif
}
skip_sapces_and_newline(it, end);
}
diff --git a/test/test_xml_nothrow.cpp b/test/test_xml_nothrow.cpp
new file mode 100644
index 00000000..c5941136
--- /dev/null
+++ b/test/test_xml_nothrow.cpp
@@ -0,0 +1,77 @@
+#define DOCTEST_CONFIG_IMPLEMENT
+#include "doctest.h"
+#undef THROW_UNKNOWN_KEY
+#include "iguana/xml_reader.hpp"
+#include "iguana/xml_writer.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum class enum_status {
+ paid,
+ unpaid,
+};
+struct order_t {
+ enum_status status;
+ float total;
+};
+REFLECTION(order_t, status, total);
+
+TEST_CASE("test unkonwn key") {
+ auto validator = [](order_t od) {
+ CHECK(od.status == enum_status::unpaid);
+ CHECK(od.total == 65.0f);
+ };
+ std::string str = R"(
+
+ 12345
+ 1
+
+
+ John
+ ]]>
+ Doe
+
+ 123 Main St
+ Anytown
+ CA
+ 12345
+
+
+
+ -
+ 67890
+ Widget A
+ 2
+ 10.00
+
+ -
+ 98765
+ Widget B
+ 3
+ 15.00
+
+
+ ]]>
+ 65.00
+
+ )";
+ order_t od;
+ iguana::from_xml(od, str);
+ validator(od);
+
+ std::string ss;
+ iguana::to_xml(od, ss);
+ order_t od1;
+ iguana::from_xml(od1, ss);
+ validator(od1);
+}
+
+// doctest comments
+// 'function' : must be 'attribute' - see issue #182
+DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007)
+int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); }
+DOCTEST_MSVC_SUPPRESS_WARNING_POP