add xml parser
This commit is contained in:
@@ -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;
|
||||
* [luaDate](https://github.com/Tieske/date) - functions for working with time;
|
||||
* [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
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ AIO Launcher включает в себя интерпретатор LuaJ 3.0.1
|
||||
* `url` - модуль с функциями для кодирования/декодирования строки в URL из библиотеки Lua Penlight;
|
||||
* [luaDate](https://github.com/Tieske/date) - функции для работы со временем;
|
||||
* [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
134
lib/xml.lua
Normal 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, "<", "<"); -- '<' -> "<"
|
||||
value = string.gsub(value, ">", ">"); -- '>' -> ">"
|
||||
value = string.gsub(value, "\"", """); -- '"' -> """
|
||||
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, """, "\"");
|
||||
value = string.gsub(value, "'", "'");
|
||||
value = string.gsub(value, ">", ">");
|
||||
value = string.gsub(value, "<", "<");
|
||||
value = string.gsub(value, "&", "&");
|
||||
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
16
samples/xml-test.lua
Normal 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
|
||||
Reference in New Issue
Block a user