summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2016-11-02 21:20:13 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2016-11-02 21:20:13 +0000
commitfeebd980e5623500ed63ed09c967fc8cf7b7ef7d (patch)
treea7f95735c5b54946d58093756a3e431fb1922afe
parentAdd exception messages to all exceptions (diff)
downloadslicer-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.jam1
-rw-r--r--slicer/test/initial/attributemap.xml6
-rw-r--r--slicer/test/initial/elementmap.xml14
-rw-r--r--slicer/test/preprocessor.cpp2
-rw-r--r--slicer/test/serializers.cpp35
-rw-r--r--slicer/test/xml.ice10
-rw-r--r--slicer/xml/serializer.cpp118
-rw-r--r--slicer/xml/serializer.h6
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 {