slabOS/lib/basalt/libraries/xmlParser.lua
2025-06-02 10:23:40 +03:00

77 lines
2.5 KiB
Lua

local XMLNode = {
new = function(tag)
return {
tag = tag,
value = nil,
attributes = {},
children = {},
addChild = function(self, child)
table.insert(self.children, child)
end,
addAttribute = function(self, tag, value)
self.attributes[tag] = value
end
}
end
}
local parseAttributes = function(node, s)
-- Parse "" style string attributes
local _, _ = string.gsub(s, "(%w+)=([\"'])(.-)%2", function(attribute, _, value)
node:addAttribute(attribute, "\"" .. value .. "\"")
end)
-- Parse {} style computed attributes
local _, _ = string.gsub(s, "(%w+)={(.-)}", function(attribute, expression)
node:addAttribute(attribute, expression)
end)
end
local XMLParser = {
parseText = function(xmlText)
local stack = {}
local top = XMLNode.new()
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 "") .. text
stack[#stack].value = lVal
end
if empty == "/" then -- empty element tag
local lNode = XMLNode.new(label)
parseAttributes(lNode, xarg)
top:addChild(lNode)
elseif c == "" then -- start tag
local lNode = XMLNode.new(label)
parseAttributes(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.tag ~= label then
error("XMLParser: trying to close " .. toclose.tag .. " 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].tag)
end
return top.children
end
}
return XMLParser