-- This file is generated from teal-src/util/datamapper.lua
if not math.type then
require ( " prosody.util.mathcompat " )
end
local st = require ( " prosody.util.stanza " ) ;
local pointer = require ( " prosody.util.jsonpointer " ) ;
local schema_t = { }
local function toboolean ( s )
if s == " true " or s == " 1 " then
return true
elseif s == " false " or s == " 0 " then
return false
elseif s then
return true
end
end
local function totype ( t , s )
if not s then
return nil
end
if t == " string " then
return s
elseif t == " boolean " then
return toboolean ( s )
elseif t == " number " or t == " integer " then
return tonumber ( s )
end
end
local value_goes = { }
local function resolve_schema ( schema , root )
if type ( schema ) == " table " then
if schema [ " $ref " ] and schema [ " $ref " ] : sub ( 1 , 1 ) == " # " then
return pointer.resolve ( root , schema [ " $ref " ] : sub ( 2 ) )
end
end
return schema
end
local function guess_schema_type ( schema )
local schema_types = schema.type
if type ( schema_types ) == " string " then
return schema_types
elseif schema_types ~= nil then
error ( " schema has unsupported 'type' property " )
elseif schema.properties then
return " object "
elseif schema.items then
return " array "
end
return " string "
end
local function unpack_propschema ( propschema , propname , current_ns )
local proptype = " string "
local value_where = propname and " in_text_tag " or " in_text "
local name = propname
util.datamapper: Deal with locally built stanzas missing xmlns
So the problem is that xmlns is not inherited when building a stanza,
and then :get_child(n, ns) with an explicit namespace does not find that
such child tags.
E.g.
local t = st.stanza("foo", { xmlns = "urn:example:bar" })
:text_tag("hello", "world");
assert(t:get_child("hello", "urn:example:bar"), "This fails");
Meanwhile, during parsing (util.xmppstream or util.xml) child tags do
get the parents xmlns when not overriding them.
Thus, in the above example, if the stanza is passed trough
`t = util.xml.parse(tostring(t))` then the assert succeeds.
This change makes it so that it leaves out the namespace argument to
:get_child when it is the same as the current/parent namespace, which
behaves the same for both built and parsed stanzas.
5 years ago
local namespace
local prefix
local single_attribute
local enums
if type ( propschema ) == " table " then
proptype = guess_schema_type ( propschema ) ;
elseif type ( propschema ) == " string " then
error ( " schema as string is not supported: " .. propschema .. " { " .. current_ns .. " } " .. propname )
end
if proptype == " object " or proptype == " array " then
value_where = " in_children "
end
if type ( propschema ) == " table " then
local xml = propschema.xml
if xml then
if xml.name then
name = xml.name
end
util.datamapper: Deal with locally built stanzas missing xmlns
So the problem is that xmlns is not inherited when building a stanza,
and then :get_child(n, ns) with an explicit namespace does not find that
such child tags.
E.g.
local t = st.stanza("foo", { xmlns = "urn:example:bar" })
:text_tag("hello", "world");
assert(t:get_child("hello", "urn:example:bar"), "This fails");
Meanwhile, during parsing (util.xmppstream or util.xml) child tags do
get the parents xmlns when not overriding them.
Thus, in the above example, if the stanza is passed trough
`t = util.xml.parse(tostring(t))` then the assert succeeds.
This change makes it so that it leaves out the namespace argument to
:get_child when it is the same as the current/parent namespace, which
behaves the same for both built and parsed stanzas.
5 years ago
if xml.namespace and xml.namespace ~= current_ns then
namespace = xml.namespace
end
if xml.prefix then
prefix = xml.prefix
end
if proptype == " array " and xml.wrapped then
value_where = " in_wrapper "
elseif xml.attribute then
value_where = " in_attribute "
elseif xml.text then
value_where = " in_text "
elseif xml.x_name_is_value then
value_where = " in_tag_name "
elseif xml.x_single_attribute then
single_attribute = xml.x_single_attribute
value_where = " in_single_attribute "
end
end
if propschema [ " const " ] then
enums = { propschema [ " const " ] }
elseif propschema [ " enum " ] then
enums = propschema [ " enum " ]
end
end
return proptype , value_where , name , namespace , prefix , single_attribute , enums
end
local parse_object
local parse_array
local function extract_value ( s , value_where , proptype , name , namespace , prefix , single_attribute , enums )
if value_where == " in_tag_name " then
local c
if proptype == " boolean " then
c = s : get_child ( name , namespace ) ;
elseif enums and proptype == " string " then
for i = 1 , # enums do
c = s : get_child ( enums [ i ] , namespace ) ;
if c then
break
end
end
else
c = s : get_child ( nil , namespace ) ;
end
if c then
return c.name
end
elseif value_where == " in_attribute " then
local attr = name
if prefix then
attr = prefix .. " : " .. name
util.datamapper: Deal with locally built stanzas missing xmlns
So the problem is that xmlns is not inherited when building a stanza,
and then :get_child(n, ns) with an explicit namespace does not find that
such child tags.
E.g.
local t = st.stanza("foo", { xmlns = "urn:example:bar" })
:text_tag("hello", "world");
assert(t:get_child("hello", "urn:example:bar"), "This fails");
Meanwhile, during parsing (util.xmppstream or util.xml) child tags do
get the parents xmlns when not overriding them.
Thus, in the above example, if the stanza is passed trough
`t = util.xml.parse(tostring(t))` then the assert succeeds.
This change makes it so that it leaves out the namespace argument to
:get_child when it is the same as the current/parent namespace, which
behaves the same for both built and parsed stanzas.
5 years ago
elseif namespace and namespace ~= s.attr . xmlns then
attr = namespace .. " \1 " .. name
end
return s.attr [ attr ]
elseif value_where == " in_text " then
return s : get_text ( )
elseif value_where == " in_single_attribute " then
local c = s : get_child ( name , namespace )
return c and c.attr [ single_attribute ]
elseif value_where == " in_text_tag " then
return s : get_child_text ( name , namespace )
end
end
function parse_object ( schema , s , root )
local out = { }
schema = resolve_schema ( schema , root )
if type ( schema ) == " table " and schema.properties then
for prop , propschema in pairs ( schema.properties ) do
propschema = resolve_schema ( propschema , root )
local proptype , value_where , name , namespace , prefix , single_attribute , enums = unpack_propschema ( propschema , prop , s.attr . xmlns )
if value_where == " in_children " and type ( propschema ) == " table " then
if proptype == " object " then
local c = s : get_child ( name , namespace )
if c then
out [ prop ] = parse_object ( propschema , c , root ) ;
end
elseif proptype == " array " then
local a = parse_array ( propschema , s , root ) ;
if a and a [ 1 ] ~= nil then
out [ prop ] = a ;
end
else
error ( " unreachable " )
end
elseif value_where == " in_wrapper " and type ( propschema ) == " table " and proptype == " array " then
local wrapper = s : get_child ( name , namespace ) ;
if wrapper then
out [ prop ] = parse_array ( propschema , wrapper , root ) ;
end
else
local value = extract_value ( s , value_where , proptype , name , namespace , prefix , single_attribute , enums )
out [ prop ] = totype ( proptype , value )
end
end
end
return out
end
function parse_array ( schema , s , root )
local itemschema = resolve_schema ( schema.items , root ) ;
local proptype , value_where , child_name , namespace , prefix , single_attribute , enums = unpack_propschema ( itemschema , nil , s.attr . xmlns )
local attr_name
if value_where == " in_single_attribute " then
value_where = " in_attribute " ;
attr_name = single_attribute ;
end
local out = { }
if proptype == " object " then
if type ( itemschema ) == " table " then
for c in s : childtags ( child_name , namespace ) do
table.insert ( out , parse_object ( itemschema , c , root ) ) ;
end
else
error ( " array items must be schema object " )
end
elseif proptype == " array " then
if type ( itemschema ) == " table " then
for c in s : childtags ( child_name , namespace ) do
table.insert ( out , parse_array ( itemschema , c , root ) ) ;
end
end
else
for c in s : childtags ( child_name , namespace ) do
local value = extract_value ( c , value_where , proptype , attr_name or child_name , namespace , prefix , single_attribute , enums )
table.insert ( out , totype ( proptype , value ) ) ;
end
end
return out
end
local function parse ( schema , s )
local s_type = guess_schema_type ( schema )
if s_type == " object " then
return parse_object ( schema , s , schema )
elseif s_type == " array " then
return parse_array ( schema , s , schema )
else
error ( " top-level scalars unsupported " )
end
end
local function toxmlstring ( proptype , v )
if proptype == " string " and type ( v ) == " string " then
return v
elseif proptype == " number " and type ( v ) == " number " then
return string.format ( " %g " , v )
elseif proptype == " integer " and type ( v ) == " number " then
return string.format ( " %d " , v )
elseif proptype == " boolean " then
return v and " 1 " or " 0 "
end
end
local unparse
local function unparse_property ( out , v , proptype , propschema , value_where , name , namespace , current_ns , prefix ,
single_attribute , root )
if value_where == " in_attribute " then
local attr = name
if prefix then
attr = prefix .. " : " .. name
util.datamapper: Deal with locally built stanzas missing xmlns
So the problem is that xmlns is not inherited when building a stanza,
and then :get_child(n, ns) with an explicit namespace does not find that
such child tags.
E.g.
local t = st.stanza("foo", { xmlns = "urn:example:bar" })
:text_tag("hello", "world");
assert(t:get_child("hello", "urn:example:bar"), "This fails");
Meanwhile, during parsing (util.xmppstream or util.xml) child tags do
get the parents xmlns when not overriding them.
Thus, in the above example, if the stanza is passed trough
`t = util.xml.parse(tostring(t))` then the assert succeeds.
This change makes it so that it leaves out the namespace argument to
:get_child when it is the same as the current/parent namespace, which
behaves the same for both built and parsed stanzas.
5 years ago
elseif namespace and namespace ~= current_ns then
attr = namespace .. " \1 " .. name
end
out.attr [ attr ] = toxmlstring ( proptype , v )
elseif value_where == " in_text " then
out : text ( toxmlstring ( proptype , v ) )
elseif value_where == " in_single_attribute " then
assert ( single_attribute )
local propattr = { }
util.datamapper: Deal with locally built stanzas missing xmlns
So the problem is that xmlns is not inherited when building a stanza,
and then :get_child(n, ns) with an explicit namespace does not find that
such child tags.
E.g.
local t = st.stanza("foo", { xmlns = "urn:example:bar" })
:text_tag("hello", "world");
assert(t:get_child("hello", "urn:example:bar"), "This fails");
Meanwhile, during parsing (util.xmppstream or util.xml) child tags do
get the parents xmlns when not overriding them.
Thus, in the above example, if the stanza is passed trough
`t = util.xml.parse(tostring(t))` then the assert succeeds.
This change makes it so that it leaves out the namespace argument to
:get_child when it is the same as the current/parent namespace, which
behaves the same for both built and parsed stanzas.
5 years ago
if namespace and namespace ~= current_ns then
propattr.xmlns = namespace
end
propattr [ single_attribute ] = toxmlstring ( proptype , v )
out : tag ( name , propattr ) : up ( ) ;
else
local propattr
if namespace ~= current_ns then
propattr = { xmlns = namespace }
end
if value_where == " in_tag_name " then
if proptype == " string " and type ( v ) == " string " then
out : tag ( v , propattr ) : up ( ) ;
elseif proptype == " boolean " and v == true then
out : tag ( name , propattr ) : up ( ) ;
end
elseif proptype == " object " and type ( propschema ) == " table " and type ( v ) == " table " then
local c = unparse ( propschema , v , name , namespace , nil , root ) ;
if c then
out : add_direct_child ( c ) ;
end
elseif proptype == " array " and type ( propschema ) == " table " and type ( v ) == " table " then
if value_where == " in_wrapper " then
local c = unparse ( propschema , v , name , namespace , nil , root ) ;
if c then
out : add_direct_child ( c ) ;
end
else
unparse ( propschema , v , name , namespace , out , root ) ;
end
else
out : text_tag ( name , toxmlstring ( proptype , v ) , propattr )
end
end
end
function unparse ( schema , t , current_name , current_ns , ctx , root )
if root == nil then
root = schema
end
if schema.xml then
if schema.xml . name then
current_name = schema.xml . name
end
if schema.xml . namespace then
current_ns = schema.xml . namespace
end
end
local out = ctx or st.stanza ( current_name , { xmlns = current_ns } )
local s_type = guess_schema_type ( schema )
if s_type == " object " then
for prop , propschema in pairs ( schema.properties ) do
propschema = resolve_schema ( propschema , root )
local v = t [ prop ]
if v ~= nil then
local proptype , value_where , name , namespace , prefix , single_attribute = unpack_propschema ( propschema , prop , current_ns )
unparse_property ( out , v , proptype , propschema , value_where , name , namespace , current_ns , prefix , single_attribute , root )
end
end
return out
elseif s_type == " array " then
local itemschema = resolve_schema ( schema.items , root )
local proptype , value_where , name , namespace , prefix , single_attribute = unpack_propschema ( itemschema , current_name , current_ns )
for _ , item in ipairs ( t ) do
unparse_property ( out , item , proptype , itemschema , value_where , name , namespace , current_ns , prefix , single_attribute , root )
end
return out
end
end
return { parse = parse ; unparse = unparse }