Voila, je voulais savoir a tout hasard si cela existait ... apparament pas vraiment. Voici donc ma solution qui utilise le langage lua ( http://lua.org/ )
#! /usr/bin/env lua
-- fichier : template.lua
-------------------------------------------------------------------------------
--
-- Copyright (C) 2006 Mildred.
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to
-- deal in the Software without restriction, including without limitation the
-- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-- sell copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-- IN THE SOFTWARE.
--
-------------------------------------------------------------------------------
--lw = require("lwbase").install()
local env = { tmplchar="#", IN_TEMPLATE=true }
setmetatable(env, {__index=_G})
function env.out(...)
env.output(...)
end
function env.finnish()
end
local process_line_buffer = {}
local process_line_has_buffer = false
function env.process_line(line, n)
if process_line_has_buffer then
if line:sub(-1) == "\\" then
table.insert(process_line_buffer, line:sub(1, -2))
else
table.insert(process_line_buffer, line)
process_line_has_buffer = false
local b = table.concat(process_line_buffer, "\n")
process_line_buffer = {}
local f = assert(loadstring(b, ("template '%s' line %i to %i"):format(env.filename, n+1-#process_line_buffer, n)))
setfenv(f, env)
f()
end
elseif line:sub(1, 1) == "#" then
if line:sub(2, 2) == "#" then
env.out(line:sub(2).."\n")
elseif line:sub(-1) == "\\" then
table.insert(process_line_buffer, line:sub(2, -2))
process_line_has_buffer = true
else
local f = assert(loadstring(line:sub(2), ("template '%s' line %i"):format(env.filename, n)))
setfenv(f, env)
f()
end
else
env.out(line.."\n")
end
end
local function main(filename)
filename = filename or arg[0]
env.filename = filename
env.output = io.write
local f = assert(io.open(filename, "r"))
local line = f:read("*l")
local n = 1;
if line:sub(1, 1) == "#" then
line = f:read("*l")
n = n + 1
end
local buffer = {}
while line and line ~= "" do
table.insert(buffer, line);
line = f:read("*l")
n = n + 1
end
line = f:read("*l")
buffer = table.concat(buffer, "\n")
local func = assert(loadstring(buffer, ("template '%s' header"):format(filename)))
setfenv(func, env)
func()
while line do
env.process_line(line, n)
line = f:read("*l")
n = n + 1
end
env.finnish()
f:close();
end
local lisp_any
local function lisp_space(s, n)
while s:sub(n, n):find("%s") do
n = n + 1
end
return n
end
local function lisp_list(s, n)
local o, t, ty, idf
t = {}
n, o, ty = lisp_any(s, n)
idf = 1 -- tag
--print("end", ty, n)
while o do
if idf then
t[idf] = o
idf = nil
elseif ty == "idf" then
if o:sub(1, 1) == ":" then
t[o]=true
else
idf = o
end
elseif ty == "longstring" then
for k, v in ipairs(o) do
table.insert(t, v)
end
else
table.insert(t, o)
end
n, o, ty = lisp_any(s, n)
--print("end", ty, n)
end
if type(idf)=="string" then
table.insert(t, idf)
end
return n, t, "list"
end
local function lisp_idf(s, n)
local m = s:find("[%s%)]", n)
if not m then
return n, nil, nil
end
return m, s:sub(n, m-1), "idf"
end
local function lisp_string(s, n, stop)
local str, m
str = {}
stop = stop or '"'
local continue = true
while continue do
m = s:find(stop, n, true)
table.insert(str, s:sub(n, m-1))
--print("str", "'"..s:sub(n, m-1).."'")
if s:sub(m+1, m+1) == stop then
--print("str", "esc")
table.insert(str, stop)
n = m + 2
else
n = m + 1
continue = false
end
end
--print("str res", table.concat(str))
return n+1, table.concat(str), "string"
end
local function lisp_longstring(s, n, stop, esc)
local str, m, t
str = {}
t = {}
stop = stop or '"'
esc = esc or ','
while true do
m = s:find("[%"..stop.."%"..esc.."]", n)
table.insert(str, s:sub(n, m-1))
if s:sub(m, m) == esc and s:sub(m+1, m+1) == '(' then
table.insert(t, table.concat(str))
str = {}
local o
n, o = lisp_list(s, m+2)
table.insert(t, o)
elseif s:sub(m+1, m+1) == stop then
table.insert(str, stop)
n = m + 2
else
table.insert(t, table.concat(str))
str = {}
n = m + 1
break
end
end
return n, t, "longstring"
end
function lisp_any(s, n)
local c
n = n or 1
--print("space", n)
n = lisp_space(s, n)
c = s:sub(n, n)
if c == "(" then
--print("list", n, "'"..s:sub(n, n).."'")
return lisp_list(s, n+1)
elseif c == ")" then
--print("endlist", n, "'"..s:sub(n, n).."'")
return n+1, nil, nil
elseif c == '"' then
--print("string", n)
return lisp_string(s, n+1, '"')
elseif c == "[" then
--print("longstring", n)
return lisp_longstring(s, n+1, ']')
else
--print("idf", n, "'"..s:sub(n, n).."'");
return lisp_idf(s, n)
end
end
function env.lisp(s)
return select(2, lisp_any(s))
end
function env.makexml(tree, indent, lvl)
lvl = lvl or 0
local nl, tab = "", ""
local inc_level = 0
if indent then
assert(type(indent)=="table", "2nd parameter must be a table")
indent.tab = indent.tab or "\t"
indent.nl = indent.nl or "\n"
if not indent.disable then
nl = indent.nl
tab = indent.tab
inc_level = 1
end
else
indent = {tab="", nl=""}
end
if type(tree) == "string" then
return (tab:rep(lvl)..tree:gsub("&", "&"):gsub("<", "<"):gsub(">", ">")..nl)
else
local tagname = table.remove(tree, 1)
local tag = {tab:rep(lvl), "<", tagname}
local old_indent_disable = indent.disable
for k, v in pairs(tree) do
if k == "indent:" and (v == "false" or v == "0") or k==":inline" then
indent.disable=true
nl = ""
tab = ""
inc_level = 0
elseif k == "indent:" and (v == "true" or v == "1") or k==":block" then
indent.disable=false
nl = indent.nl
tab = indent.tab
inc_level = 1
elseif type(k) == "string" then
table.insert(tag, " " .. k .. '="' .. env.makexml(tostring(v)) .. '"')
end
end
if #tree > 0 then
table.insert(tag, ">")
if not indent.disable then table.insert(tag, nl) end
for k, v in ipairs(tree) do
table.insert(tag, (env.makexml(v, indent, lvl+inc_level)))
end
if not indent.disable then table.insert(tag, tab:rep(lvl)) end
table.insert(tag, "</" .. tagname .. ">")
else
table.insert(tag, "/>")
end
indent.disable = old_indent_disable
if not indent.disable then table.insert(tag, indent.nl) end
return (table.concat(tag))
end
end
if debug.getinfo(3) == nil then
return main(...)
else
return main
end
L'appel se fait avec une commande du type ./template.lua montemplate. Le résultat est sur la sortie standard. Un template ressemble à :
local buffer = {}
function out(str)
table.insert(buffer, str)
end
function finnish()
local tree = lisp(table.concat(buffer))
output(makexml(tree, {tab=" ", nl="\n", disable=true}), "\n")
end
(html :block
(head
(title :inline abc))
# out " (body"
(p :inline [te,(a href test abc)st])))
pour un résultat :
< html >
< head >
< title >abc< /title >
< /head >
< body >
< p >te< a href="test" >abc< /a >st< /p >
< /body >
< /html >
La syntaxe est du style lisp. Un tag commence par "(" suivi du nom du tag et se termine par ")". Les paramètres du tag peut être remplis en ajoutant entre les parenthèses le nom du paramètre (sans quotes) suivi de sa valeur. Les chaines sont entourées de quotes ou de crochets "[", "]". A l'interieur des crochets, on peut ajouter des tags en préfixant la parenthèse ouvrante par "," (comme avec la quasiquotation). Pas encore de commentaires, c'est à venir. Voila
# petite création
Posté par Mildred (site web personnel) . En réponse au message langage pour écrire du XML. Évalué à 2.
#! /usr/bin/env lua -- fichier : template.lua ------------------------------------------------------------------------------- -- -- Copyright (C) 2006 Mildred. -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to -- deal in the Software without restriction, including without limitation the -- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -- sell copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -- IN THE SOFTWARE. -- ------------------------------------------------------------------------------- --lw = require("lwbase").install() local env = { tmplchar="#", IN_TEMPLATE=true } setmetatable(env, {__index=_G}) function env.out(...) env.output(...) end function env.finnish() end local process_line_buffer = {} local process_line_has_buffer = false function env.process_line(line, n) if process_line_has_buffer then if line:sub(-1) == "\\" then table.insert(process_line_buffer, line:sub(1, -2)) else table.insert(process_line_buffer, line) process_line_has_buffer = false local b = table.concat(process_line_buffer, "\n") process_line_buffer = {} local f = assert(loadstring(b, ("template '%s' line %i to %i"):format(env.filename, n+1-#process_line_buffer, n))) setfenv(f, env) f() end elseif line:sub(1, 1) == "#" then if line:sub(2, 2) == "#" then env.out(line:sub(2).."\n") elseif line:sub(-1) == "\\" then table.insert(process_line_buffer, line:sub(2, -2)) process_line_has_buffer = true else local f = assert(loadstring(line:sub(2), ("template '%s' line %i"):format(env.filename, n))) setfenv(f, env) f() end else env.out(line.."\n") end end local function main(filename) filename = filename or arg[0] env.filename = filename env.output = io.write local f = assert(io.open(filename, "r")) local line = f:read("*l") local n = 1; if line:sub(1, 1) == "#" then line = f:read("*l") n = n + 1 end local buffer = {} while line and line ~= "" do table.insert(buffer, line); line = f:read("*l") n = n + 1 end line = f:read("*l") buffer = table.concat(buffer, "\n") local func = assert(loadstring(buffer, ("template '%s' header"):format(filename))) setfenv(func, env) func() while line do env.process_line(line, n) line = f:read("*l") n = n + 1 end env.finnish() f:close(); end local lisp_any local function lisp_space(s, n) while s:sub(n, n):find("%s") do n = n + 1 end return n end local function lisp_list(s, n) local o, t, ty, idf t = {} n, o, ty = lisp_any(s, n) idf = 1 -- tag --print("end", ty, n) while o do if idf then t[idf] = o idf = nil elseif ty == "idf" then if o:sub(1, 1) == ":" then t[o]=true else idf = o end elseif ty == "longstring" then for k, v in ipairs(o) do table.insert(t, v) end else table.insert(t, o) end n, o, ty = lisp_any(s, n) --print("end", ty, n) end if type(idf)=="string" then table.insert(t, idf) end return n, t, "list" end local function lisp_idf(s, n) local m = s:find("[%s%)]", n) if not m then return n, nil, nil end return m, s:sub(n, m-1), "idf" end local function lisp_string(s, n, stop) local str, m str = {} stop = stop or '"' local continue = true while continue do m = s:find(stop, n, true) table.insert(str, s:sub(n, m-1)) --print("str", "'"..s:sub(n, m-1).."'") if s:sub(m+1, m+1) == stop then --print("str", "esc") table.insert(str, stop) n = m + 2 else n = m + 1 continue = false end end --print("str res", table.concat(str)) return n+1, table.concat(str), "string" end local function lisp_longstring(s, n, stop, esc) local str, m, t str = {} t = {} stop = stop or '"' esc = esc or ',' while true do m = s:find("[%"..stop.."%"..esc.."]", n) table.insert(str, s:sub(n, m-1)) if s:sub(m, m) == esc and s:sub(m+1, m+1) == '(' then table.insert(t, table.concat(str)) str = {} local o n, o = lisp_list(s, m+2) table.insert(t, o) elseif s:sub(m+1, m+1) == stop then table.insert(str, stop) n = m + 2 else table.insert(t, table.concat(str)) str = {} n = m + 1 break end end return n, t, "longstring" end function lisp_any(s, n) local c n = n or 1 --print("space", n) n = lisp_space(s, n) c = s:sub(n, n) if c == "(" then --print("list", n, "'"..s:sub(n, n).."'") return lisp_list(s, n+1) elseif c == ")" then --print("endlist", n, "'"..s:sub(n, n).."'") return n+1, nil, nil elseif c == '"' then --print("string", n) return lisp_string(s, n+1, '"') elseif c == "[" then --print("longstring", n) return lisp_longstring(s, n+1, ']') else --print("idf", n, "'"..s:sub(n, n).."'"); return lisp_idf(s, n) end end function env.lisp(s) return select(2, lisp_any(s)) end function env.makexml(tree, indent, lvl) lvl = lvl or 0 local nl, tab = "", "" local inc_level = 0 if indent then assert(type(indent)=="table", "2nd parameter must be a table") indent.tab = indent.tab or "\t" indent.nl = indent.nl or "\n" if not indent.disable then nl = indent.nl tab = indent.tab inc_level = 1 end else indent = {tab="", nl=""} end if type(tree) == "string" then return (tab:rep(lvl)..tree:gsub("&", "&"):gsub("<", "<"):gsub(">", ">")..nl) else local tagname = table.remove(tree, 1) local tag = {tab:rep(lvl), "<", tagname} local old_indent_disable = indent.disable for k, v in pairs(tree) do if k == "indent:" and (v == "false" or v == "0") or k==":inline" then indent.disable=true nl = "" tab = "" inc_level = 0 elseif k == "indent:" and (v == "true" or v == "1") or k==":block" then indent.disable=false nl = indent.nl tab = indent.tab inc_level = 1 elseif type(k) == "string" then table.insert(tag, " " .. k .. '="' .. env.makexml(tostring(v)) .. '"') end end if #tree > 0 then table.insert(tag, ">") if not indent.disable then table.insert(tag, nl) end for k, v in ipairs(tree) do table.insert(tag, (env.makexml(v, indent, lvl+inc_level))) end if not indent.disable then table.insert(tag, tab:rep(lvl)) end table.insert(tag, "</" .. tagname .. ">") else table.insert(tag, "/>") end indent.disable = old_indent_disable if not indent.disable then table.insert(tag, indent.nl) end return (table.concat(tag)) end end if debug.getinfo(3) == nil then return main(...) else return main endL'appel se fait avec une commande du type ./template.lua montemplate. Le résultat est sur la sortie standard. Un template ressemble à :local buffer = {} function out(str) table.insert(buffer, str) end function finnish() local tree = lisp(table.concat(buffer)) output(makexml(tree, {tab=" ", nl="\n", disable=true}), "\n") end (html :block (head (title :inline abc)) # out " (body" (p :inline [te,(a href test abc)st])))pour un résultat : La syntaxe est du style lisp. Un tag commence par "(" suivi du nom du tag et se termine par ")". Les paramètres du tag peut être remplis en ajoutant entre les parenthèses le nom du paramètre (sans quotes) suivi de sa valeur. Les chaines sont entourées de quotes ou de crochets "[", "]". A l'interieur des crochets, on peut ajouter des tags en préfixant la parenthèse ouvrante par "," (comme avec la quasiquotation). Pas encore de commentaires, c'est à venir. Voila