Skip to content

Commit

Permalink
xerces-plugin-arrays: add deserialization support for multiple elemen…
Browse files Browse the repository at this point in the history
…ts with the same parent (map to elektra array) ElektraInitiative#1280
  • Loading branch information
e1528532 committed Apr 3, 2017
1 parent 3f80bac commit 5477dbd
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/plugins/xerces/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ add_plugin (xerces
${XercesC_INCLUDE_DIRS}
LINK_LIBRARIES
${XercesC_LIBRARIES}
LINK_ELEKTRA
elektra-meta
INSTALL_TEST_DATA
)

Expand Down
82 changes: 65 additions & 17 deletions src/plugins/xerces/deserializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@

#include <algorithm>
#include <iostream>
#include <locale>
#include <map>

#include <kdbease.h>
#include <kdblogger.h>
#include <key.hpp>
#include <locale>

XERCES_CPP_NAMESPACE_USE
using namespace std;
Expand Down Expand Up @@ -48,10 +51,7 @@ string trim (string const & str)
while (getline (ss, to, '\n'))
{
// Remove whitespace lines, most likely caused by pretty printing
if (!all_of (to.begin (), to.end (), [](char c) { return isspace (c, locale ()); }))
{
trimmed += to;
}
if (!all_of (to.begin (), to.end (), [](char c) { return isspace (c, locale ()); })) trimmed += to;
}

return trimmed;
Expand All @@ -74,10 +74,18 @@ string getElementText (DOMNode const * parent)
return trim (str);
}

Key newNodeKey (Key const & parent, DOMNode const * node)
{
Key childKey (parent.getFullName (), KEY_END);
const string keyName = toStr (node->getNodeName ());
childKey.addBaseName (keyName);
return childKey;
}

void node2key (DOMNode const * n, Key const & parent, KeySet const & ks, Key & current)
{
const string keyName = toStr (n->getNodeName ());
ELEKTRA_LOG_DEBUG ("Encountered Element: %s", keyName.c_str ());
ELEKTRA_LOG_DEBUG ("Encountered Element: %s with parent %s", keyName.c_str (), current.getFullName ().c_str ());

if (!ks.size ())
{ // we map the parent key to the xml root element
Expand All @@ -90,17 +98,12 @@ void node2key (DOMNode const * n, Key const & parent, KeySet const & ks, Key & c
}
}
else
{
current.addBaseName (keyName);
}

const string text = getElementText (n);
current.set<string> (text);

if (!current.isValid ())
{
throw XercesPluginException ("Given keyset contains invalid keys to serialize");
}
if (!current.isValid ()) throw XercesPluginException ("Given keyset contains invalid keys to serialize");

ELEKTRA_LOG_DEBUG ("new parent is %s with value %s", current.getFullName ().c_str (), current.get<string> ().c_str ());

Expand All @@ -119,23 +122,67 @@ void node2key (DOMNode const * n, Key const & parent, KeySet const & ks, Key & c
}
}

void dom2keyset (DOMNode const * n, Key const & parent, KeySet & ks)
void analyzeMultipleElements (DOMNode const * n, Key const & current, map<Key, bool> & arrays)
{
for (auto child = n->getFirstChild (); child != 0; child = child->getNextSibling ())
{
Key childKey = newNodeKey (current, child);

auto it = arrays.find (childKey);
if (it != arrays.end ())
{
if (!it->second)
{
ELEKTRA_LOG_DEBUG ("There are multiple elements of %s, mapping this as an array",
childKey.getFullName ().c_str ());
arrays[childKey] = true;
}
}
else
arrays[childKey] = false;
}
}

Key newArrayKey (Key const & arrayKey, KeySet & ks)
{
KeySet result (elektraArrayGet (arrayKey.getKey (), ks.getKeySet ()));
if (!result.size ())
{
Key arrayBaseKey = arrayKey.dup ();
arrayBaseKey.addBaseName ("#");
result.append (arrayBaseKey);
}
return Key (elektraArrayGetNextKey (result.getKeySet ()));
}

void dom2keyset (DOMNode const * n, Key const & parent, KeySet & ks, map<Key, bool> & arrays)
{
if (n)
{
Key current (parent.getFullName (), KEY_END);

if (n->getNodeType () == DOMNode::ELEMENT_NODE)
{
node2key (n, parent, ks, current);
// Only add keys with a value, attributes or leafs or the root to preserve the original name
if (n->hasAttributes () || !current.getString ().empty () || !n->getFirstChild () || !ks.size ())

auto it = arrays.find (current);
const bool array = it != arrays.end () && it->second;
// Multiple elements with that name, map as an array
if (array) current = newArrayKey (current, ks);

// Only add keys with a value, attributes or leafs or the root to preserve the original name or array keys
if (n->hasAttributes () || !current.getString ().empty () || !n->getFirstChild () || !ks.size () || array)
{
ELEKTRA_LOG_DEBUG ("adding %s", current.getFullName ().c_str ());
ks.append (current);
}
else
ELEKTRA_LOG_DEBUG ("skipping %s", current.getFullName ().c_str ());
}
// the first level cannot have more children so its enough to check that here
analyzeMultipleElements (n, current, arrays);
for (auto child = n->getFirstChild (); child != 0; child = child->getNextSibling ())
dom2keyset (child, current, ks);
dom2keyset (child, current, ks, arrays);
}
}

Expand All @@ -149,5 +196,6 @@ void xerces::deserialize (Key const & parentKey, KeySet & ks)
ELEKTRA_LOG_DEBUG ("deserializing relative to %s from file %s", parentKey.getFullName ().c_str (),
parentKey.get<string> ().c_str ());
auto document = doc2dom (parentKey.get<string> ());
if (document) dom2keyset (document->getDocumentElement (), parentKey, ks);
map<Key, bool> arrays;
if (document) dom2keyset (document->getDocumentElement (), parentKey, ks, arrays);
}
2 changes: 1 addition & 1 deletion src/plugins/xerces/xerces/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
<artifactId>log4j-core</artifactId>
<version>2.0-rc2</version>
</dependency>
<!-- <dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.3</version>
Expand Down

0 comments on commit 5477dbd

Please sign in to comment.