forked from Minebea-Intec/zbssvn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsvnxml.lua
168 lines (148 loc) · 3.26 KB
/
svnxml.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/lua
--============================================================
-- JJvB's micro XML-parser
-- slightly adapted for svn's --xml output
--============================================================
--
-- cache most used functions
--
local find=string.find
local push=table.insert
local qt={quot='"',apos='\'',lt='<',gt='>',amp='&'}
local function unquote(str)
return (str:gsub("&(%w+);",qt))
end
--
-- xml element metatable
--
local xml_mt={}
xml_mt.__index=xml_mt
function xml_mt:tag()
return self[1]
end
function xml_mt:cdata()
local cdata=self[2]
if cdata and type(cdata)=="string" then return cdata end
return nil,"no cdata in <"..self:tag()..">"
end
function xml_mt:element(name)
for i=2,#self do
local obj=self[i]
if obj[1]==name then
return obj,i
end
end
return nil,"no element <"..tostring(name).."> in <"..self:tag()..">"
end
function xml_mt:elements()
local n=1
return function()
n=n+1
local elem=self[n]
if elem then return elem,n end
end
end
function xml_mt:attribute(name)
local attr=self[name]
if attr then return attr end
return nil,"no attribute "..tostring(name).." in <"..self:tag()..">"
end
--
-- substitute for %q
--
local st={['\n']='\\n',['\r']='\\r',['\t']='\\t',['\"']='\\"',['\\']='\\\\'}
local function vis(val,len)
if type(val)~="string" then return tostring(val) end
if len and #val>len then return vis(val:sub(1,len)).."..." end
return '"'..(val:gsub("[\r\n\t\"\\]",st))..'"'
end
--
-- the XML parser
--
local function parsestr(str)
local pos=1
-- helper for parse error
local function fail(msg)
error(msg.." at "..vis(str:sub(pos),60),2)
end
-- helper to iterate over attributes
local function namval()
local a,b,nam,val=find(str,'^%s+([%w-]+)="([^"]+)"',pos)
if a then pos=b+1 return nam,val end
end
local function need_obj()
--
-- begin tag
--
local a,b,tag=find(str,'^<([%w-]+)',pos)
if not a then fail("expected '<tag'") end
pos=b+1
--
-- attributes
--
local obj=setmetatable({tag},xml_mt)
for nam,val in namval do obj[nam]=unquote(val) end
--
-- quick end-of-tag
--
local a,b=find(str,'^/>%s*',pos)
if a then
pos=b+1
return obj
end
--
-- end-of tag
--
local a,b=find(str,'^>%s*',pos)
if not a then fail("expected '>'") end
pos=b+1
--
-- any elements?
--
while not find(str,"^</",pos) do
if find(str,'^<',pos) then
push(obj,need_obj())
else
local a,b,cdata=find(str,"^([^<>]+)%s*<",pos)
if not a then fail("Expected literal") end
pos=b+1-1 -- exclude '<'
push(obj,unquote(cdata))
end
end
--
-- closing tag
--
local a,b,etag=find(str,'^</([%w-]+)>%s*',pos)
if not a then fail("expected end-of-tag "..vis(tag)) end
if etag~=tag then fail("tag mismatch "..vis(tag).." vs "..vis(etag))end
pos=b+1
return obj
end
--
-- check for document prolog (ignored for svn)
--
local xmlobj
local a,b,xmltag=find(str,"<(%?%w+)",pos)
if a then
pos=b+1
xmlobj={xmltag}
for nam,val in namval do xmlobj[nam]=val end
local a,b=find(str,'^%?>%s*',pos)
if not a then fail("expected '?>'") end
pos=b+1
end
--
-- get the one and only top object in xml
--
local obj=need_obj()
--
-- check
--
if pos<=#str then
fail("expected no more data")
end
return obj
end
local svnxml={}
svnxml.parsestr=parsestr
return svnxml