src/lxp/lom.lua

Fri, 23 Apr 2021 21:15:05 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Fri, 23 Apr 2021 21:15:05 +0100
changeset 36
4a61f00ee916
parent 10
e981a82571cf
permissions
-rw-r--r--

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,
}

mercurial