diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2016-11-02 21:20:13 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2016-11-02 21:20:13 +0000 |
commit | feebd980e5623500ed63ed09c967fc8cf7b7ef7d (patch) | |
tree | a7f95735c5b54946d58093756a3e431fb1922afe | |
parent | Add exception messages to all exceptions (diff) | |
download | slicer-1.4.2.tar.bz2 slicer-1.4.2.tar.xz slicer-1.4.2.zip |
Support [de]serializing XML elements/attributes to/from a dictionaryslicer-1.4.2
-rw-r--r-- | slicer/test/Jamfile.jam | 1 | ||||
-rw-r--r-- | slicer/test/initial/attributemap.xml | 6 | ||||
-rw-r--r-- | slicer/test/initial/elementmap.xml | 14 | ||||
-rw-r--r-- | slicer/test/preprocessor.cpp | 2 | ||||
-rw-r--r-- | slicer/test/serializers.cpp | 35 | ||||
-rw-r--r-- | slicer/test/xml.ice | 10 | ||||
-rw-r--r-- | slicer/xml/serializer.cpp | 118 | ||||
-rw-r--r-- | slicer/xml/serializer.h | 6 |
8 files changed, 173 insertions, 19 deletions
diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam index 4046e6f..53a9489 100644 --- a/slicer/test/Jamfile.jam +++ b/slicer/test/Jamfile.jam @@ -64,6 +64,7 @@ run preprocessor.cpp <library>adhocutil <include>.. <library>../tool//slicer-compiler + <dependency>types : preprocess ; diff --git a/slicer/test/initial/attributemap.xml b/slicer/test/initial/attributemap.xml new file mode 100644 index 0000000..7651ac6 --- /dev/null +++ b/slicer/test/initial/attributemap.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Maps> + <amap a="one" b="two" c="three"/> + <emap/> + <rmap/> +</Maps> diff --git a/slicer/test/initial/elementmap.xml b/slicer/test/initial/elementmap.xml new file mode 100644 index 0000000..1f8d913 --- /dev/null +++ b/slicer/test/initial/elementmap.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Maps> + <amap/> + <emap> + <a>one</a> + <b>two</b> + <c>three</c> + </emap> + <rmap> + <a Id="1">one</a> + <b Id="2">two</b> + <c Id="3">three</c> + </rmap> +</Maps> diff --git a/slicer/test/preprocessor.cpp b/slicer/test/preprocessor.cpp index 7431a2d..cd2cd8d 100644 --- a/slicer/test/preprocessor.cpp +++ b/slicer/test/preprocessor.cpp @@ -20,7 +20,7 @@ ComponentsCount COMPONENTS_IN_TEST_ICE = { { "inheritance.ice", 12 }, { "interfaces.ice", 0 }, { "json.ice", 2 }, - { "xml.ice", 2 }, + { "xml.ice", 5 }, { "db.ice", 4 }, { "types.ice", 3 } }; diff --git a/slicer/test/serializers.cpp b/slicer/test/serializers.cpp index 6218b3b..350d570 100644 --- a/slicer/test/serializers.cpp +++ b/slicer/test/serializers.cpp @@ -254,6 +254,31 @@ checkSomeNumbers(const TestModule::SomeNumbers & sn) } void +attributeMap(const TestXml::Maps & s) +{ + BOOST_REQUIRE_EQUAL(3, s.amap.size()); + BOOST_REQUIRE_EQUAL("one", s.amap.find("a")->second); + BOOST_REQUIRE_EQUAL("two", s.amap.find("b")->second); + BOOST_REQUIRE_EQUAL("three", s.amap.find("c")->second); +} + +void +elementMap(const TestXml::Maps & s) +{ + BOOST_REQUIRE_EQUAL(3, s.emap.size()); + BOOST_REQUIRE_EQUAL("one", s.emap.find("a")->second); + BOOST_REQUIRE_EQUAL("two", s.emap.find("b")->second); + BOOST_REQUIRE_EQUAL("three", s.emap.find("c")->second); + BOOST_REQUIRE_EQUAL(3, s.rmap.size()); + BOOST_REQUIRE_EQUAL(1, s.rmap.find("a")->second.Id); + BOOST_REQUIRE_EQUAL(2, s.rmap.find("b")->second.Id); + BOOST_REQUIRE_EQUAL(3, s.rmap.find("c")->second.Id); + BOOST_REQUIRE_EQUAL("one", s.rmap.find("a")->second.Name); + BOOST_REQUIRE_EQUAL("two", s.rmap.find("b")->second.Name); + BOOST_REQUIRE_EQUAL("three", s.rmap.find("c")->second.Name); +} + +void checkObjectMap(const TestJson::Properties & p) { BOOST_REQUIRE_EQUAL(3, p.size()); @@ -437,6 +462,16 @@ BOOST_AUTO_TEST_CASE( xml_rootEnums_xml ) verifyByFile<TestModule::SomeNumbers, Slicer::XmlFileDeserializer>("enum.xml", checkSomeNumbers); } +BOOST_AUTO_TEST_CASE( xml_attributemap_xml ) +{ + verifyByFile<TestXml::Maps, Slicer::XmlFileDeserializer>("attributemap.xml", attributeMap); +} + +BOOST_AUTO_TEST_CASE( xml_elementmap_xml ) +{ + verifyByFile<TestXml::Maps, Slicer::XmlFileDeserializer>("elementmap.xml", elementMap); +} + BOOST_AUTO_TEST_CASE( json_rootEnums_json ) { verifyByFile<TestModule::SomeNumbers, Slicer::JsonFileDeserializer>("enum2.json", checkSomeNumbers); diff --git a/slicer/test/xml.ice b/slicer/test/xml.ice index ecb50b5..6deb02f 100644 --- a/slicer/test/xml.ice +++ b/slicer/test/xml.ice @@ -16,6 +16,16 @@ module TestXml { [ "slicer:xml:text" ] string Name; }; + dictionary<string, string> StringMap; + dictionary<string, EntityRef> RefMap; + struct Maps { + [ "slicer:xml:attributes" ] + StringMap amap; + [ "slicer:xml:elements" ] + StringMap emap; + [ "slicer:xml:elements" ] + RefMap rmap; + }; }; #endif diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp index 654793c..307819a 100644 --- a/slicer/xml/serializer.cpp +++ b/slicer/xml/serializer.cpp @@ -19,6 +19,10 @@ namespace Slicer { const std::string md_attribute = "xml:attribute"; const std::string md_text = "xml:text"; const std::string md_bare = "xml:bare"; + const std::string md_attributes = "xml:attributes"; + const std::string md_elements = "xml:elements"; + const std::string keyName = "key"; + const std::string valueName = "value"; const auto defaultElementCreator = boost::bind(&xmlpp::Element::add_child, _1, _2, Glib::ustring()); static const Glib::ustring TrueText("true"); @@ -171,6 +175,75 @@ namespace Slicer { }; void + XmlDeserializer::DocumentTreeIterateDictAttrs(const xmlpp::Element::AttributeList & attrs, ModelPartPtr dict) + { + for (const auto & attr : attrs) { + auto emp = dict->GetAnonChild(); + emp->Create(); + auto key = emp->GetChild(keyName); + auto value = emp->GetChild(valueName); + key->SetValue(new XmlValueSource(attr->get_name())); + key->Complete(); + value->SetValue(new XmlValueSource(attr->get_value())); + value->Complete(); + emp->Complete(); + } + } + + void + XmlDeserializer::DocumentTreeIterateDictElements(const xmlpp::Element * element, ModelPartPtr dict) + { + auto node = element->get_first_child(); + while (node) { + if (auto element = dynamic_cast<const xmlpp::Element *>(node)) { + auto emp = dict->GetAnonChild(); + emp->Create(); + auto key = emp->GetChild(keyName); + auto value = emp->GetChildRef(valueName); + key->SetValue(new XmlValueSource(element->get_name())); + key->Complete(); + DocumentTreeIterateElement(element, value->Child(), value); + emp->Complete(); + } + node = node->get_next_sibling(); + } + } + + void + XmlDeserializer::DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartPtr smp, ChildRefPtr smpr) + { + if (auto typeIdPropName = smp->GetTypeIdProperty()) { + if (auto typeAttr = element->get_attribute(*typeIdPropName)) { + smp = smp->GetSubclassModelPart(typeAttr->get_value()); + } + } + smp->Create(); + if (metaDataFlagSet(smpr->ChildMetaData(), md_attributes)) { + auto attrs(element->get_attributes()); + if (!attrs.empty()) { + DocumentTreeIterateDictAttrs(attrs, smp); + } + } + else if (metaDataFlagSet(smpr->ChildMetaData(), md_elements)) { + DocumentTreeIterateDictElements(element, smp); + } + else { + auto attrs(element->get_attributes()); + if (!attrs.empty()) { + DocumentTreeIterate(attrs.front(), smp); + } + auto firstChild = element->get_first_child(); + if (firstChild) { + DocumentTreeIterate(firstChild, smp); + } + else { + smp->SetValue(new XmlContentValueSource()); + } + } + smp->Complete(); + } + + void XmlDeserializer::DocumentTreeIterate(const xmlpp::Node * node, ModelPartPtr mp) { while (node) { @@ -183,24 +256,7 @@ namespace Slicer { smp = smp->GetAnonChild(); } if (smp) { - if (auto typeIdPropName = smp->GetTypeIdProperty()) { - if (auto typeAttr = element->get_attribute(*typeIdPropName)) { - smp = smp->GetSubclassModelPart(typeAttr->get_value()); - } - } - smp->Create(); - auto attrs(element->get_attributes()); - if (!attrs.empty()) { - DocumentTreeIterate(attrs.front(), smp); - } - auto firstChild = element->get_first_child(); - if (firstChild) { - DocumentTreeIterate(firstChild, smp); - } - else { - smp->SetValue(new XmlContentValueSource()); - } - smp->Complete(); + DocumentTreeIterateElement(element, smp, smpr); } } } @@ -247,6 +303,12 @@ namespace Slicer { else if (hp && metaDataFlagSet(hp->GetMetadata(), md_text)) { mp->GetValue(new XmlContentValueTarget(n)); } + else if (hp && metaDataFlagSet(hp->GetMetadata(), md_attributes)) { + ModelTreeIterateDictAttrs(n->add_child(name), mp); + } + else if (hp && metaDataFlagSet(hp->GetMetadata(), md_elements)) { + ModelTreeIterateDictElements(n->add_child(name), mp); + } else { if (hp && metaDataFlagSet(hp->GetMetadata(), md_bare)) { ModelTreeProcessElement(n, mp, boost::bind(&xmlpp::Element::add_child, _1, name, Glib::ustring())); @@ -258,6 +320,26 @@ namespace Slicer { } void + XmlSerializer::ModelTreeIterateDictAttrs(xmlpp::Element * element, ModelPartPtr dict) + { + dict->OnEachChild([element](const auto &, const auto & mp, const auto &) { + mp->GetChild(keyName)->GetValue(new XmlValueTarget([&mp,element](const auto & name) { + mp->GetChild(valueName)->GetValue(new XmlAttributeValueTarget(element, name)); + })); + }); + } + + void + XmlSerializer::ModelTreeIterateDictElements(xmlpp::Element * element, ModelPartPtr dict) + { + dict->OnEachChild([element](const auto &, const auto & mp, const auto &) { + mp->GetChild(keyName)->GetValue(new XmlValueTarget([&mp,element](const auto & name) { + ModelTreeProcessElement(element->add_child(name), mp->GetChild(valueName), defaultElementCreator); + })); + }); + } + + void XmlSerializer::ModelTreeProcessElement(xmlpp::Element * element, ModelPartPtr mp, const ElementCreator & ec) { auto typeIdPropName = mp->GetTypeIdProperty(); diff --git a/slicer/xml/serializer.h b/slicer/xml/serializer.h index 23ba17a..5b56ad1 100644 --- a/slicer/xml/serializer.h +++ b/slicer/xml/serializer.h @@ -3,6 +3,7 @@ #include <slicer/serializer.h> #include <libxml++/document.h> +#include <libxml++/nodes/element.h> #include <visibility.h> namespace Slicer { @@ -14,6 +15,8 @@ namespace Slicer { protected: static void ModelTreeProcessElement(xmlpp::Element * n, ModelPartPtr mp, const ElementCreator &); + static void ModelTreeIterateDictAttrs(xmlpp::Element * element, ModelPartPtr dict); + static void ModelTreeIterateDictElements(xmlpp::Element * element, ModelPartPtr dict); }; class DLL_PUBLIC XmlStreamSerializer : public XmlSerializer { @@ -49,7 +52,10 @@ namespace Slicer { class DLL_PUBLIC XmlDeserializer : public Deserializer { protected: static void DocumentTreeIterate(const xmlpp::Node * node, ModelPartPtr mp); + static void DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartPtr mp, ChildRefPtr c); static void DocumentTreeIterate(const xmlpp::Document * doc, ModelPartPtr mp); + static void DocumentTreeIterateDictAttrs(const xmlpp::Element::AttributeList & attrs, ModelPartPtr dict); + static void DocumentTreeIterateDictElements(const xmlpp::Element * parent, ModelPartPtr dict); }; class DLL_PUBLIC XmlStreamDeserializer : public XmlDeserializer { |