Tue, 04 Jan 2011 00:23:51 +0000
util.xmppstream, util.xmllex: Basic test passes
local assert, ipairs , pairs , setmetatable , rawget , rawset , tostring = assert, ipairs , pairs , setmetatable , rawget , rawset , tostring local strsub = string.sub local tblconcat = table.concat local tblinsert = table.insert local function getstring ( msgs , startpos , finishpos ) if #msgs == 1 then --All originated in same string return strsub ( msgs[1] , startpos , finishpos ) else -- Over multiple source strings return strsub ( msgs[1] , startpos , -1 ) .. tblconcat ( msgs , "" , 2 , #msgs - 1 ) .. strsub ( msgs[#msgs] , 1 , finishpos ) end end local m_mt = { __tostring = function ( v ) local str = v.stringform if str then return str else str = getstring ( v.msgs , v.start , v.finish ) v.stringform = str return str end end } local function handleoutside ( str , r , initial ) local a , b , close = str:find ( "<(/?)" , initial ) if not a then r.state = "outside" return false end --Finalise text object local m = r[#r] m.finish = a - 1 m.type = "text" local m = setmetatable ( { msgs = { str } ; start = a ; starte = b + 1 ; } , m_mt ) if close ~= "/" then r.depth = r.depth + 1 m.type = "open" else r.depth = r.depth - 1 m.type = "close" end tblinsert ( r , m ) r.state = "inside" return true end local function handleinside ( str, r , initial ) local c , d , selfclosing = str:find ( "(/?)>" , initial ) if not c then r.state = "inside" return false end local m = r[#r] m.finish = d m.finishs = c - 1 if selfclosing == "/" then m.type = "selfclosing" r.depth = r.depth - 1 end local m = setmetatable ( { msgs = { str } ; start = d + 1 ; type = "text" ; } , m_mt ) tblinsert ( r , m ) r.state = "outside" return true end local function index ( str , r ) r = r or { depth = 0, state = "outside" } local initial = 1 if not r[#r] then r[1] = setmetatable ( { msgs = { str } ; type = "text" ; start = 1 ; } , m_mt ) else tblinsert ( r[#r].msgs , str ) end while true do if r.state == "outside" then if not handleoutside ( str , r , initial ) then break end else if not handleinside ( str , r , initial ) then break end end initial = r[#r].start end return r end local function process_starttag ( starttag ) local str = tostring ( starttag ) local attr = { } local elem = str:match ( "[^%s=></]+" ) for name , quote, attvalue in str:gmatch ( [=[([^%s=<]+)%s*=%s*(["'])([^"]*)%2]=] ) do attr [ name ] = attvalue end return elem , attr end local stanza_mt = { __index = function ( t , k ) if k == "name" or k == "attr" then local elem , attr = process_starttag ( t.opentag ) rawset ( t , "name" , elem ) rawset ( t , "attr" , attr ) return rawget ( t , k ) else print("METHOD",k) return stanza_methods [ k ] end end ; __tostring = function ( t ) local opentag = t.opentag local endtag = assert ( rawget ( t , "endtag" ) or rawget ( t , "selfclosing" ) and t.opentag ) return getstring ( opentag.msgs , opentag.start , endtag.finish ) end ; } local function new_stanza ( ) return setmetatable ( { tags = { } } , stanza_mt ) end local function tagindex_to_tree(indices) if not start then start = 1 finish = #indices end local root = { tags = { } } local leaf = root for i = start , finish do local v = indices [ i ] if v.type == "selfclosing" then local newleaf = new_stanza ( ) newleaf.opentag = v newleaf.selfclosing = true newleaf.parent = leaf tblinsert ( leaf , newleaf ) tblinsert ( leaf.tags , newleaf ) elseif v.type == "close" then -- Close tag leaf.endtag = v leaf = leaf.parent elseif v.type == "text" then tblinsert ( leaf, v ) else -- Open tag local newleaf = new_stanza ( ) newleaf.opentag = v newleaf.parent = leaf tblinsert ( leaf , newleaf ) tblinsert ( leaf.tags , newleaf ) leaf = newleaf end end assert ( leaf == root , "Mismatched opening/closing tags" ) return root; end return { index = index ; tagindex_to_tree = tagindex_to_tree ; process_starttag = process_starttag ; };