Fri, 23 Apr 2021 21:15:05 +0100
New implementation of lxp.lom by Tom?s Guisasola
-- See Copyright Notice in license.html local lxp = require "lxp" local table = require"table" local tinsert, tremove = table.insert, table.remove local assert, pairs, type = assert, pairs, type -- auxiliary functions ------------------------------------------------------- local function starttag (p, tag, attr) local stack = p:getcallbacks().stack local newelement = {tag = tag, attr = attr} tinsert(stack, newelement) end local function endtag (p, tag) local stack = p:getcallbacks().stack local element = tremove(stack) assert(element.tag == tag) local level = #stack tinsert(stack[level], element) end local function text (p, txt) local stack = p:getcallbacks().stack local element = stack[#stack] local n = #element if type(element[n]) == "string" then element[n] = element[n] .. txt else tinsert(element, txt) end end -- main function ------------------------------------------------------------- local function parse (o) local c = { StartElement = starttag, EndElement = endtag, CharacterData = text, _nonstrict = true, stack = {{}} } local p = lxp.new(c) local to = type(o) if to == "string" then local status, err, line, col, pos = p:parse(o) if not status then return nil, err, line, col, pos end else local iter, state, init if to == "table" then iter, state, init = pairs(o) elseif to == "function" then iter = o elseif to == "userdata" and o.read then iter, state = o.read, o else error ("Bad argument #1 to parse: expected a string, a table, a function or a file, but got "..to, 2) end for l in iter, state, init do local status, err, line, col, pos = p:parse(l) if not status then return nil, err, line, col, pos end end end local status, err, line, col, pos = p:parse() -- close document if not status then return nil, err, line, col, pos end p:close() return c.stack[1][1] end -- utility functions --------------------------------------------------------- local function find_elem (self, tag) if self.tag == tag then return self end for i = 1, #self do local v = self[i] if type(v) == "table" then local found = find_elem (v, tag) if found then return found end end end return nil end local function list_children (self, tag) local i = 0 return function () i = i+1 local v = self[i] while v do if type (v) == "table" and (tag == nil or tag == v.tag) then return v end i = i+1 v = self[i] end return nil end end return { find_elem = find_elem, list_children = list_children, parse = parse, }