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
|
-- an example showing 'pl.lexer' doing some serious work.
-- The resulting Lua table is in the same LOM format used by luaexpat.
-- This is (clearly) not a professional XML parser, so don't use it
-- on your homework!
local lexer = require 'pl.lexer'
local pretty = require 'pl.pretty'
local append = table.insert
local skipws,expecting = lexer.skipws,lexer.expecting
local function parse_element (tok,tag)
local tbl,t,v,attrib
tbl = {}
tbl.tag = tag -- LOM 'tag' is the element tag
t,v = skipws(tok)
while v ~= '/' and v ~= '>' do
if t ~= 'iden' then error('expecting attribute identifier') end
attrib = v
expecting(tok,'=')
v = expecting(tok,'string')
-- LOM: 'attr' subtable contains attrib/value pairs and an ordered list of attribs
if not tbl.attr then tbl.attr = {} end
tbl.attr[attrib] = v
append(tbl.attr,attrib)
t,v = skipws(tok)
end
if v == '/' then
expecting(tok,'>')
return tbl
end
-- pick up element data
t,v = tok()
while true do
if t == '<' then
t,v = skipws(tok)
if t == '/' then -- element end tag
t,v = tok()
if t == '>' then return tbl end
if t == 'iden' and v == tag then
if tok() == '>' then return tbl end
end
error('expecting end tag '..tag)
else
append(tbl,parse_element(tok,v)) -- LOM: child elements added to table
t,v = skipws(tok)
end
else
append(tbl,v) -- LOM: text added to table
t,v = skipws(tok)
end
end
end
local function parse_xml (tok)
local t = skipws(tok)
local v
while t == '<' do
t,v = tok()
if t == '?' or t == '!' then
-- skip meta stuff and commentary
repeat t = tok() until t == '>'
t = expecting(tok,'<')
else
return parse_element(tok,v)
end
end
end
local s = [[
<?xml version="1.0" encoding="UTF-8"?>
<sensor name="closure-meter-2" id="7D7D0600006F0D00" loc="100,100,0" device="closure-meter" init="true">
<detector name="closure-meter" phenomenon="closure" units="mm" id="1"
vmin="0" vmax="5000" device="closure-meter" calib="0,0;5000,5000"
sampling_interval="25000" measurement_interval="600000"
/>
</sensor>
]]
local tok = lexer.scan(s,nil,{space=false},{string=true})
local res = parse_xml(tok)
print(pretty.write(res))
|