util.datamapper
Given a declarative description of some data, lets you extract that data from an XML stanza, or turn such data into an XML stanza.
Available starting with 0.12.0.
Introduction
As with all utils, to use util.datamapper you have to import it first, by adding this line near the top of your code:
local datamapper = require "util.datamapper";
Say you have this piece of XML (from XEP-0092):
query xmlns="jabber:iq:version">
<name>Prosody</name>
<version>0.12.4</version>
<os>Linux</os>
<query> </
Just looking at it, it looks like a record, dict, object (loved child has many names) with three fields. We can describe it using a variant of JSON Schema with an extension for XML support from the OpenAPI specification, like this:
local schema = {
type = "object";
= {
xml = "query";
name = "jabber:iq:version";
namespace };
= {
properties = { type = "string" },
name = { type = "string" },
version = { type = "string" },
os },
};
Now you can extract those fields into a convenient table using the parse function.
= datamapper.parse(schema, stanza) data
The data
variable should now hold a table like this:
= {
data ="Prosody";
name="0.12.4";
version="Linux";
os}
If you want to turn the data back into XML, you can do that using the unparse function
= datamapper.unparse(schema, data) stanza
Of course, the above could instead have been written like this:
-- parse-equivalent
= {
data = stanza:get_child_text("name");
name = stanza:get_child_text("version");
version = stanza:get_child_text("os");
os }
-- unparse-equivalent
= st.stanza("query", { xmlns = "jabber:iq:version" })
stanza :text_tag("name", "Prosody")
:text_tag("version", "0.12.4")
:text_tag("os", "Linux")
:reset();
For such a simple case as this, you probably should,
util.datamapper
is a pretty big and complex library. But
the more complex XML you have to deal with, the more complicated code it
will spare you from writing. Especially when dealing with deeply nested
trees of optional elements, where you have to check whether each child
element really was included or risk an
attempt to index a nil value
error.
More (and more complicated) examples can be found for example in the
test
cases for util.datamapper
Reference
schema
Example
local = {
type = "object";
= {
xml = "query";
name = "jabber:iq:version";
namespace };
= {
properties = "string";
name = "string";
version = "string";
os };
};
This describes an XML stanza (from XEP-0092) looking like this:
query xmlns="jabber:iq:version">
<name>Prosody</name>
<version>0.12.4</version>
<os>Linux</os>
<query> </
parse
= datamapper.parse(schema, stanza)
data -- This might give you a table like:
= {
data ="Prosody";
name="0.12.4";
version="Linux";
os}
unparse
= datamapper.unparse(schema, data)
stanza -- would give you back the XML snippet from earlier
Recognised JSON Schema subset
$ref
-
A Schema with a JSON Pointer in a
$ref
field is replaced by the pointed-to Schema. type
- Only as a single type name string, arrays are not understood.
enum
- Only supported in combination with tag names as value.
const
-
Treated as an
enum
field with a single value. items
- Supported.
properties
- Supported.
XML schema extension
In addition to the xml
fields described in OpenAPI, the
following experimental extension fields are supported:
text
- Boolean. Signifies that this is the text content of the current element, for use in combination with attributes.
x_name_is_value
-
Boolean. Enables behavior to treat the element name as the value. Meant
for use with empty tags (
<example/>
) where the tag name itself is part of an enumeration, or is to be treated as a truthy value if it is present. x_single_attribute
- String. Name of attribute to use as the value for simplifying treatment of XML elements that only carry a single value in an attribute.