--[[ /* * 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.8 2007-05-30 17:59:50 pixel Exp $ */ ]]-- local xml_replacements = { { "&", "&" }, { "<", "<" }, { ">", ">" }, } local attribute_replacements = { { '"', '\\"' }, } local function generic_escape(str, replacements) local _, r for _, r in pairs(replacements) do str = string.gsub(str, r[1], r[2]) end return str end local function xml_escape(str) return generic_escape(str, xml_replacements) end local 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 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 do_render_r(v, depth) local middle, i, n = "" if v.__objname == "Handle" then local r = "" while not v:isclosed() do r = r .. v:read() .. "\n" end return r elseif v.type == "comment" then return space_indent(depth) .. "\n" elseif v.type == "lf" then return "\n" elseif type(v.key) == "string" then if type(v.nodes) == "table" then for i, n in ipairs(v.nodes) do if type(n) == "string" then middle = middle .. "\n" .. n elseif type(n) == "table" then middle = middle .. "\n" .. do_render_r(n, depth + 1) .. "\n" .. space_indent(depth) end end return space_indent(depth) .. "<" .. v.key .. render_attrs(v.attrs) .. ">" .. middle .. "" else return space_indent(depth) .. "<" .. v.key .. render_attrs(v.attrs) .. " />" 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, tops = {}, render = do_render, doctype = '', } setmetatable(r, xmlmarkup_metatable) return r end --[[ example of use: result = [[ Test Normal test
Bold test. ]] xm = NewXmlMarkup() xm:html { xm:head { xm:title "Test" }, xm:body { bgcolor = "#ffeedd", "Normal test", xm:br(), xm:b "Bold test.", xm:comment "Hi there...", } } print(xm:render()) ]]--