--[[ /* * Baltisot * Copyright (C) 1999-2007 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: xmllib.lua,v 1.17 2007-08-06 14:59:45 pixel Exp $ */ ]]-- local xml_replacements = { { "&", "&" }, { "<", "<" }, { ">", ">" }, } local attribute_replacements = { { '"', '\\"' }, } function xml_escape(str) return generic_escape(str, xml_replacements) end function attribute_escape(str) return generic_escape(str, attribute_replacements) end local function process_comment(xm, a) return { istop = true, nodes = { a }, type = "comment", } end local function process_lf(xm) return { istop = true, type = "lf", } end local function process_raw(xm, a) return { istop = true, nodes = { a }, type = "raw", } end local function process_cdata(xm, a) return { istop = true, nodes = { a }, type = "cdata", } end local function process_jcdata(xm, a) return { istop = true, nodes = { a }, type = "jcdata", } end local function process_empty(xm) return { istop = true, type = "empty", } end local function burrow(xm, t) local k, v if type(t) ~= "table" then return end if type(t.istop) ~= "boolean" then return end t.istop = nil end local function clean_tops(t) local k, v for k, v in pairs(t) do if not v.istop then t[k] = nil end end end local function process_tag(xm, key, a) local ret, attrs, nodes, has_nodes, has_attrs, k, v, b = { istop = true, key = key }, {}, {}, false, false if type(a) == "string" then a = { a } end if type(a) == "nil" then a = {} end if type(a) ~= "table" then error("Wrong argument type: " .. type(a)) end if a.__objname == nil then for k, v in ipairs(a) do if type(v) == "table" then burrow(xm, v) has_nodes = true table.insert(nodes, v) elseif type(v) == "string" then has_nodes = true table.insert(nodes, xml_escape(v)) else error "Unsupported argument type." end end for k, v in pairs(a) do if (type(k) == "string") then has_attrs = true attrs[k] = attribute_escape(xml_escape(v)) end end else if a.__objname == "Handle" then has_nodes = true table.insert(nodes, a) else error "Can't handle objects which are not Handles." end end if (has_nodes) then ret.nodes = nodes end if (has_attrs) then ret.attrs = attrs end table.insert(xm.tops, ret) clean_tops(xm.tops) return ret end local function render_attrs(t) local r, k, v = "" if type(t) ~= "table" then return "" end for k, v in pairs(t) do if v ~= "" then r = r .. " " .. k .. '="' .. v .. '"' else r = r .. " " .. k end end return r end local function space_indent(depth) return string.rep(" ", 4 * depth) end local function render_comment(depth, v) return space_indent(depth) .. "\n", true end local function render_lf(depth, v) return "\n", true end local function render_raw(depth, v) return v.nodes[1], true end local function render_cdata(depth, v) return "", true end local function render_jcdata(depth, v) return "//", true end local function render_empty(depth, v) return "", false end local special_renders = { comment = render_comment, lf = render_lf, raw = render_raw, cdata = render_cdata, jcdata = render_jcdata, empty = render_empty, } local function do_render_r(v, depth) local middle, i, n, rec, enters, r_enters = "" if v.__objname == "Handle" then local r = "" while not v:isclosed() do r = r .. v:read() .. "\n" end return r, true elseif type(v.type) == "string" and type(special_renders[v.type]) == "function" then return special_renders[v.type](depth, v) elseif type(v.key) == "string" then if type(v.nodes) == "table" then enters = false for i, n in ipairs(v.nodes) do if type(n) == "string" then if middle ~= "" then middle = middle .. "\n" .. n enters = true else middle = n end elseif type(n) == "table" then rec, r_enters = do_render_r(n, depth + 1) if enters or r_enters or middle ~= "" then middle = middle .. "\n" .. rec .. "\n" .. space_indent(depth) else middle = rec end end end return space_indent(depth) .. "<" .. v.key .. render_attrs(v.attrs) .. ">" .. middle .. "" .. v.key .. ">", true else return space_indent(depth) .. "<" .. v.key .. render_attrs(v.attrs) .. " />", true end else error "Inconsistancy in the XML structure." end return "" end local function do_render(xm) local r, i, n = "" for i, n in pairs(xm.tops) do r = r .. do_render_r(n, 0) end return xm.doctype .. "\n" .. r .. "\n" end local xmlmarkup_metatable = { __index = function(xm, key) local k = key return function(xm, a) return process_tag(xm, k, a) end end } function NewXmlMarkup() local r = { comment = process_comment, lf = process_lf, raw = process_raw, cdata = process_cdata, jcdata = process_jcdata, empty = process_empty, tops = {}, render = do_render, doctype = '', } setmetatable(r, xmlmarkup_metatable) return r end function get_xml_section(t, s, norecurs, matches) local found, r function get_xml_section_r(t, s, norecurs, matches) local k, v, found, r for k, v in pairs(t) do if type(v) == "table" then if v.name == s then if type(matches) == "table" then local mk, mv found = true for mk, mv in pairs(matches) do if not string.match(v.attr[mk], mv) then found = false end end if not found then if not norecurs then found, r = get_xml_section_r(v, s, norecurs, matches) if found then return true, r end end else return true, v end else return true, v end else if not norecurs then found, r = get_xml_section_r(v, s, norecurs, matches) if found then return true, r end end end end end return false, nil end found, r = get_xml_section_r(t, s, norecurs, matches) return r end --[[ example of use: result = [=[