-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathxl.lua
99 lines (89 loc) · 2.09 KB
/
xl.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
-- XL: a poor man's XML parser in pure Lua
-- parser stolen from http://lua-users.org/wiki/LuaXml
--
-- example usage:
--
-- require 'xl'
--
-- parser = XL:new()
-- parser:from_file(arg[1])
--
-- find the first 'A' element
-- a = parser:find(parser:root(), 'A')
--
-- Copyright 2009: hans@hpelbers.org
-- This is freeware
XL = {}
function XL:new()
local x = {}
setmetatable(x, self)
self.__index = self
return x
end
function XL._get_attrs(s)
local arg = {}
string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a)
arg[w] = a
end)
return arg
end
function XL:root()
for _, v in ipairs(self.xml) do
if v.tag then return v end
end
return nil
end
function XL:find(x, t)
r = {}
for _, v in ipairs(x) do
if v.tag and v.tag == t then r[#r+1] = v end
end
return r
end
function XL:from_file(s)
local f=io.open(s)
self:from_string(f:read('*all'))
f:close()
end
function XL:from_string(s)
self.xml = nil -- reset
local stack = {}
local top = {}
table.insert(stack, top)
local ni,c,tag,attr, empty
local i, j = 1, 1
while true do
ni,j,c,tag,attr, empty = string.find(s, "<(%/?)([%w:]+)(.-)(%/?)>", i)
if not ni then break end
local text = string.sub(s, i, ni-1)
if not string.find(text, "^%s*$") then
table.insert(top, text)
end
if empty == "/" then -- empty element tag
table.insert(top, {tag=tag, attr=self._get_attrs(attr)})
elseif c == "" then -- start tag
top = {tag=tag, attr=self._get_attrs(attr)}
table.insert(stack, top) -- new level
else -- end tag
local toclose = table.remove(stack) -- remove top
top = stack[#stack]
if #stack < 1 then
error("nothing to close with "..tag)
end
if toclose.tag ~= tag then
error("trying to close "..toclose.tag.." with "..tag)
end
table.insert(top, toclose)
end
i = j+1
end
local text = string.sub(s, i)
if not string.find(text, "^%s*$") then
table.insert(stack[#stack], text)
end
if #stack > 1 then
error("unclosed "..stack[stack.n].tag)
end
self.xml = stack[1]
end
return XL