add xml parser

This commit is contained in:
Evgeny
2021-08-20 00:16:51 +03:00
parent 96b0d03328
commit 851e0fffd8
4 changed files with 152 additions and 2 deletions

View File

@@ -193,7 +193,7 @@ The kit also includes:
* `url` - a module with functions for encoding / decoding a string in a URL from the Lua Penlight library; * `url` - a module with functions for encoding / decoding a string in a URL from the Lua Penlight library;
* [luaDate](https://github.com/Tieske/date) - functions for working with time; * [luaDate](https://github.com/Tieske/date) - functions for working with time;
* [json.lua](https://github.com/rxi/json.lua) - JSON parser; * [json.lua](https://github.com/rxi/json.lua) - JSON parser;
* [SLAXDOM](https://github.com/Phrogz/SLAXML) - XML parser. * [Lua-Simple-XML-Parser](https://github.com/Cluain/Lua-Simple-XML-Parser) - XML parser (see example `xml-test.lua`).
# Metadata # Metadata

View File

@@ -193,7 +193,7 @@ AIO Launcher включает в себя интерпретатор LuaJ 3.0.1
* `url` - модуль с функциями для кодирования/декодирования строки в URL из библиотеки Lua Penlight; * `url` - модуль с функциями для кодирования/декодирования строки в URL из библиотеки Lua Penlight;
* [luaDate](https://github.com/Tieske/date) - функции для работы со временем; * [luaDate](https://github.com/Tieske/date) - функции для работы со временем;
* [json.lua](https://github.com/rxi/json.lua) - парзер JSON; * [json.lua](https://github.com/rxi/json.lua) - парзер JSON;
* [SLAXDOM](https://github.com/Phrogz/SLAXML) - парзер XML; * [Lua-Simple-XML-Parser](https://github.com/Cluain/Lua-Simple-XML-Parser) - парзер XML (см. пример `xml-test.lua`).
# Метаданные # Метаданные

134
lib/xml.lua Normal file
View File

@@ -0,0 +1,134 @@
XmlParser = {};
local function newNode(name)
local node = {}
node.___value = nil
node.___name = name
node.___children = {}
node.___props = {}
function node:value() return self.___value end
function node:setValue(val) self.___value = val end
function node:name() return self.___name end
function node:setName(name) self.___name = name end
function node:children() return self.___children end
function node:numChildren() return #self.___children end
function node:addChild(child)
if self[child:name()] ~= nil then
if type(self[child:name()].name) == "function" then
local tempTable = {}
table.insert(tempTable, self[child:name()])
self[child:name()] = tempTable
end
table.insert(self[child:name()], child)
else
self[child:name()] = child
end
table.insert(self.___children, child)
end
function node:properties() return self.___props end
function node:numProperties() return #self.___props end
function node:addProperty(name, value)
local lName = "@" .. name
if self[lName] ~= nil then
if type(self[lName]) == "string" then
local tempTable = {}
table.insert(tempTable, self[lName])
self[lName] = tempTable
end
table.insert(self[lName], value)
else
self[lName] = value
end
table.insert(self.___props, { name = name, value = self[name] })
end
return node
end
function XmlParser:ToXmlString(value)
value = string.gsub(value, "&", "&"); -- '&' -> "&"
value = string.gsub(value, "<", "&lt;"); -- '<' -> "&lt;"
value = string.gsub(value, ">", "&gt;"); -- '>' -> "&gt;"
value = string.gsub(value, "\"", "&quot;"); -- '"' -> "&quot;"
value = string.gsub(value, "([^%w%&%;%p%\t% ])",
function(c)
return string.format("&#x%X;", string.byte(c))
end);
return value;
end
function XmlParser:FromXmlString(value)
value = string.gsub(value, "&#x([%x]+)%;",
function(h)
return string.char(tonumber(h, 16))
end);
value = string.gsub(value, "&#([0-9]+)%;",
function(h)
return string.char(tonumber(h, 10))
end);
value = string.gsub(value, "&quot;", "\"");
value = string.gsub(value, "&apos;", "'");
value = string.gsub(value, "&gt;", ">");
value = string.gsub(value, "&lt;", "<");
value = string.gsub(value, "&amp;", "&");
return value;
end
function XmlParser:ParseArgs(node, s)
string.gsub(s, "(%w+)=([\"'])(.-)%2", function(w, _, a)
node:addProperty(w, self:FromXmlString(a))
end)
end
function XmlParser:ParseXmlText(xmlText)
local stack = {}
local top = newNode()
table.insert(stack, top)
local ni, c, label, xarg, empty
local i, j = 1, 1
while true do
ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w_:]+)(.-)(%/?)>", i)
if not ni then break end
local text = string.sub(xmlText, i, ni - 1);
if not string.find(text, "^%s*$") then
local lVal = (top:value() or "") .. self:FromXmlString(text)
stack[#stack]:setValue(lVal)
end
if empty == "/" then -- empty element tag
local lNode = newNode(label)
self:ParseArgs(lNode, xarg)
top:addChild(lNode)
elseif c == "" then -- start tag
local lNode = newNode(label)
self:ParseArgs(lNode, xarg)
table.insert(stack, lNode)
top = lNode
else -- end tag
local toclose = table.remove(stack) -- remove top
top = stack[#stack]
if #stack < 1 then
error("XmlParser: nothing to close with " .. label)
end
if toclose:name() ~= label then
error("XmlParser: trying to close " .. toclose.name .. " with " .. label)
end
top:addChild(toclose)
end
i = j + 1
end
local text = string.sub(xmlText, i);
if #stack > 1 then
error("XmlParser: unclosed " .. stack[#stack]:name())
end
return top
end
function XmlParser:parse(text)
return ParseXmlText(text)
end
return XmlParser

16
samples/xml-test.lua Normal file
View File

@@ -0,0 +1,16 @@
local xml = require "xml"
local test_xml =
[[
<test one="two">
<three four="five" four="six"/>
<three>eight</three>
<nine ten="eleven">twelve</nine>
</test>
]]
function on_resume()
local parsed = xml:parse(test_xml)
ui:show_text(parsed.test["@one"])
end