Merge 0.10->trunk
[prosody.git] / util / xml.lua
1
2 local st = require "util.stanza";
3 local lxp = require "lxp";
4
5 local _ENV = nil;
6
7 local parse_xml = (function()
8         local ns_prefixes = {
9                 ["http://www.w3.org/XML/1998/namespace"] = "xml";
10         };
11         local ns_separator = "\1";
12         local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
13         return function(xml)
14                 --luacheck: ignore 212/self
15                 local handler = {};
16                 local stanza = st.stanza("root");
17                 local namespaces = {}
18                 function handler:StartNamespaceDecl(prefix, url)
19                         if prefix ~= nil then
20                                 namespaces[prefix] = url
21                         end
22                 end
23                 function handler:EndNamespaceDecl(prefix)
24                         if prefix ~= nil then
25                                 namespaces[prefix] = nil
26                         end
27                 end
28                 function handler:StartElement(tagname, attr)
29                         local curr_ns,name = tagname:match(ns_pattern);
30                         if name == "" then
31                                 curr_ns, name = "", curr_ns;
32                         end
33                         if curr_ns ~= "" then
34                                 attr.xmlns = curr_ns;
35                         end
36                         for i=1,#attr do
37                                 local k = attr[i];
38                                 attr[i] = nil;
39                                 local ns, nm = k:match(ns_pattern);
40                                 if nm ~= "" then
41                                         ns = ns_prefixes[ns];
42                                         if ns then
43                                                 attr[ns..":"..nm] = attr[k];
44                                                 attr[k] = nil;
45                                         end
46                                 end
47                         end
48                         local n = {}
49                         for prefix, url in pairs(namespaces) do
50                                 n[prefix] = url
51                         end
52                         stanza:tag(name, attr, n);
53                 end
54                 function handler:CharacterData(data)
55                         stanza:text(data);
56                 end
57                 function handler:EndElement()
58                         stanza:up();
59                 end
60                 local parser = lxp.new(handler, "\1");
61                 local ok, err, line, col = parser:parse(xml);
62                 if ok then ok, err, line, col = parser:parse(); end
63                 --parser:close();
64                 if ok then
65                         return stanza.tags[1];
66                 else
67                         return ok, err.." (line "..line..", col "..col..")";
68                 end
69         end;
70 end)();
71
72 return {
73         parse = parse_xml;
74 };