diff options
author | Mojca Miklavec <mojca.miklavec@gmail.com> | 2012-05-14 17:38:55 +0000 |
---|---|---|
committer | Mojca Miklavec <mojca.miklavec@gmail.com> | 2012-05-14 17:38:55 +0000 |
commit | 15995e10bfc68edf79970c4ea4fbb6678566c46e (patch) | |
tree | 2de7ca2a83f2d37ef043ad7429a5cb945bb79ddb /Master/texmf-dist/tex/context/base/lxml-tex.lua | |
parent | c9a39f716f1e5ec820ed3aab2c9aef25c5a9d730 (diff) |
ConTeXt 2012.05.14 16:00
git-svn-id: svn://tug.org/texlive/trunk@26371 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/lxml-tex.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/lxml-tex.lua | 869 |
1 files changed, 538 insertions, 331 deletions
diff --git a/Master/texmf-dist/tex/context/base/lxml-tex.lua b/Master/texmf-dist/tex/context/base/lxml-tex.lua index 26a8b29962e..22f98980528 100644 --- a/Master/texmf-dist/tex/context/base/lxml-tex.lua +++ b/Master/texmf-dist/tex/context/base/lxml-tex.lua @@ -6,9 +6,13 @@ if not modules then modules = { } end modules ['lxml-tst'] = { license = "see context related readme files" } +-- Because we split and resolve entities we use the direct printing +-- interface and not the context one. If we ever do that there will +-- be an cldf-xml helper library. + local utf = unicode.utf8 -local utfchar = utf.char +local utfchar, utfupper = utf.char, utf.upper local concat, insert, remove = table.concat, table.insert, table.remove local format, sub, gsub, find, gmatch, match = string.format, string.sub, string.gsub, string.find, string.gmatch, string.match local type, next, tonumber, tostring = type, next, tonumber, tostring @@ -18,16 +22,18 @@ local P, S, C, Cc = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc local tex, xml = tex, xml local lowerchars, upperchars, lettered = characters.lower, characters.upper, characters.lettered -lxml = lxml or { } +lxml = lxml or { } local lxml = lxml -local texsprint, texprint, texwrite = tex.sprint, tex.print, tex.write -local texcatcodes, ctxcatcodes, vrbcatcodes, notcatcodes = tex.texcatcodes, tex.ctxcatcodes, tex.vrbcatcodes, tex.notcatcodes +local ctxcatcodes, notcatcodes = tex.ctxcatcodes, tex.notcatcodes + +local contextsprint = context.sprint -- with catcodes (here we use fast variants, but with option for tracing) local xmlelements, xmlcollected, xmlsetproperty = xml.elements, xml.collected, xml.setproperty local xmlwithelements = xml.withelements local xmlserialize, xmlcollect, xmltext, xmltostring = xml.serialize, xml.collect, xml.text, xml.tostring local xmlapplylpath = xml.applylpath +local xmlunprivatized, xmlprivatetoken, xmlprivatecodes = xml.unprivatized, xml.privatetoken, xml.privatecodes local variables = (interfaces and interfaces.variables) or { } @@ -39,8 +45,95 @@ local trace_setups = false trackers.register("lxml.setups", function(v) tra local trace_loading = false trackers.register("lxml.loading", function(v) trace_loading = v end) local trace_access = false trackers.register("lxml.access", function(v) trace_access = v end) local trace_comments = false trackers.register("lxml.comments", function(v) trace_comments = v end) +local trace_entities = false trackers.register("xml.entities", function(v) trace_entities = v end) local report_lxml = logs.reporter("xml","tex") +local report_xml = logs.reporter("xml","tex") + +local forceraw, rawroot = false, nil + +-- tex entities +-- +-- todo: unprivatize attributes + +lxml.entities = lxml.entities or { } + +storage.register("lxml/entities",lxml.entities,"lxml.entities") + +--~ xml.placeholders.unknown_any_entity = nil -- has to be per xml + +local xmlentities = xml.entities +local texentities = lxml.entities +local parsedentity = xml.parsedentitylpeg + +function lxml.registerentity(key,value) + texentities[key] = value + if trace_entities then + report_xml("registering tex entity '%s' as: %s",key,value) + end +end + +function lxml.resolvedentity(str) + if forceraw then + if trace_entities then + report_xml("passing entity '%s' as &%s;",str,str) + end + context("&%s;",str) + else + local e = texentities[str] + if e then + local te = type(e) + if te == "function" then + if trace_entities then + report_xml("passing entity '%s' using function",str) + end + e(str) + elseif e then + if trace_entities then + report_xml("passing entity '%s' as '%s'using ctxcatcodes",str,e) + end + context(e) + end + return + end + local e = xmlentities[str] + if e then + local te = type(e) + if te == "function" then + e = e(str) + end + if e then + if trace_entities then + report_xml("passing entity '%s' as '%s' using notcatcodes",str,e) + end + contextsprint(notcatcodes,e) + return + end + end + -- resolve hex and dec, todo: escape # & etc for ctxcatcodes + -- normally this is already solved while loading the file + local chr, err = lpegmatch(parsedentity,str) + if chr then + if trace_entities then + report_xml("passing entity '%s' as '%s' using ctxcatcodes",str,chr) + end + context(chr) + elseif err then + if trace_entities then + report_xml("passing faulty entity '%s' as '%s'",str,err) + end + context(err) + else + local tag = utfupper(str) + if trace_entities then + report_xml("passing entity '%s' to \\xmle using tag '%s'",str,tag) + end + context.xmle(str,tag) -- we need to use our own upper + end + end +end + +-- tex interface lxml.loaded = lxml.loaded or { } local loaded = lxml.loaded @@ -55,112 +148,68 @@ local finalizers = xml.finalizers finalizers.xml = finalizers.xml or { } finalizers.tex = finalizers.tex or { } --- this might look inefficient but it's actually rather efficient --- because we avoid tokenization of leading spaces and xml can be --- rather verbose (indented) +-- serialization with entity handling -local newline = lpeg.patterns.newline -local space = lpeg.patterns.spacer local ampersand = P("&") local semicolon = P(";") -local spacing = newline * space^0 -local content = C((1-spacing-ampersand)^1) -local verbose = C((1-(space+newline))^1) -local entity = ampersand * C((1-semicolon)^1) * semicolon - -local xmltextcapture = ( - space^0 * newline^2 * Cc("") / texprint + -- better ^-2 ? - space^0 * newline * space^0 * Cc(" ") / texsprint + - content / function(str) return texsprint(notcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes - entity / xml.resolvedentity -)^0 - -local ctxtextcapture = ( - space^0 * newline^2 * Cc("") / texprint + -- better ^-2 ? - space^0 * newline * space^0 * Cc(" ") / texsprint + - content / function(str) return texsprint(ctxcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes - entity / xml.resolvedentity -)^0 - -local forceraw, rawroot = false, nil +local entity = ampersand * C((1-semicolon)^1) * semicolon / lxml.resolvedentity -- context.bold -function lxml.startraw() - forceraw = true -end +local _, xmltextcapture = context.newtexthandler { + exception = entity, + catcodes = notcatcodes, +} -function lxml.stopraw() - forceraw = false -end +local _, xmlspacecapture = context.newtexthandler { + endofline = context.xmlcdataobeyedline, + emptyline = context.xmlcdataobeyedline, + simpleline = context.xmlcdataobeyedline, + space = context.xmlcdataobeyedspace, + exception = entity, + catcodes = notcatcodes, +} -function lxml.rawroot() - return rawroot -end +local _, xmllinecapture = context.newtexthandler { + endofline = context.xmlcdataobeyedline, + emptyline = context.xmlcdataobeyedline, + simpleline = context.xmlcdataobeyedline, + exception = entity, + catcodes = notcatcodes, +} ---~ function lxml.rawpath(rootid) ---~ if rawroot and type(rawroot) == "table" then ---~ local text, path, rp ---~ if not rawroot.dt then ---~ text, path, rp = "text", "", rawroot[0] ---~ else ---~ path, rp = "tree", "", rawroot.__p__ ---~ end ---~ while rp do ---~ local rptg = rp.tg ---~ if rptg then ---~ path = rptg .. "/" .. path ---~ end ---~ rp = rp.__p__ ---~ end ---~ return { rootid, "/" .. path, text } ---~ end ---~ end +local _, ctxtextcapture = context.newtexthandler { + exception = entity, + catcodes = ctxcatcodes, +} -- cdata -local linecommand = "\\obeyedline" -local spacecommand = "\\obeyedspace" -- "\\strut\\obeyedspace" -local beforecommand = "" -local aftercommand = "" - -local xmlverbosecapture = ( - newline / function( ) texsprint(texcatcodes,linecommand,"{}") end + - verbose / function(s) texsprint(vrbcatcodes,s) end + - space / function( ) texsprint(texcatcodes,spacecommand,"{}") end -)^0 - -local function toverbatim(str) - if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end - lpegmatch(xmlverbosecapture,str) - if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end -end +local toverbatim = context.newverbosehandler { + line = context.xmlcdataobeyedline, + space = context.xmlcdataobeyedspace, + before = context.xmlcdatabefore, + after = context.xmlcdataafter, +} -function lxml.setverbatim(before,after,obeyedline,obeyedspace) - beforecommand, aftercommand, linecommand, spacecommand = before, after, obeyedline, obeyedspace -end +lxml.toverbatim = context.newverbosehandler { + line = context.xmlcdataobeyedline, + space = context.xmlcdataobeyedspace, + before = context.xmlcdatabefore, + after = context.xmlcdataafter, + strip = true, +} -local obeycdata = true +-- raw flushing -function lxml.setcdata() - obeycdata = true +function lxml.startraw() + forceraw = true end -function lxml.resetcdata() - obeycdata = false +function lxml.stopraw() + forceraw = false end --- cdata and verbatim - -lxml.setverbatim("\\xmlcdatabefore", "\\xmlcdataafter", "\\xmlcdataobeyedline", "\\xmlcdataobeyedspace") - --- local capture = (space^0*newline)^0 * capture * (space+newline)^0 * -1 - -function lxml.toverbatim(str) - if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end - -- todo: add this to capture - str = gsub(str,"^[ \t]+[\n\r]+","") - str = gsub(str,"[ \t\n\r]+$","") - lpegmatch(xmlverbosecapture,str) - if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end +function lxml.rawroot() + return rawroot end -- storage @@ -303,22 +352,23 @@ end function lxml.withindex(name,n,command) -- will change as name is always there now local i, p = lpegmatch(splitter,n) if p then - texsprint(ctxcatcodes,"\\xmlw{",command,"}{",n,"}") + contextsprint(ctxcatcodes,"\\xmlw{",command,"}{",n,"}") else - texsprint(ctxcatcodes,"\\xmlw{",command,"}{",name,"::",n,"}") + contextsprint(ctxcatcodes,"\\xmlw{",command,"}{",name,"::",n,"}") end end function lxml.getindex(name,n) -- will change as name is always there now local i, p = lpegmatch(splitter,n) if p then - texsprint(ctxcatcodes,n) + contextsprint(ctxcatcodes,n) else - texsprint(ctxcatcodes,name,"::",n) + contextsprint(ctxcatcodes,name,"::",n) end end --- loading (to be redone, no overload) +-- loading (to be redone, no overload) .. best use different methods and +-- keep raw xml (at least as option) xml.originalload = xml.originalload or xml.load @@ -333,28 +383,29 @@ function xml.load(filename,settings) return xmltable end -local entities = xml.entities - local function entityconverter(id,str) - return entities[str] and "&"..str..";" -- feed back into tex end later + return xmlentities[str] or xmlprivatetoken(str) or "" -- roundtrip handler end function lxml.convert(id,data,entities,compress) - local settings = { - unify_predefined_entities = true, + local settings = { -- we're now roundtrip anyway + unify_predefined_entities = true, + utfize_entities = true, + resolve_predefined_entities = true, + resolve_entities = function(str) return entityconverter(id,str) end, -- needed for mathml } if compress and compress == variables.yes then settings.strip_cm_and_dt = true end - if entities and entities == variables.yes then - settings.utfize_entities = true - settings.resolve_entities = function (str) return entityconverter(id,str) end - end + -- if entities and entities == variables.yes then + -- settings.utfize_entities = true + -- -- settings.resolve_entities = function (str) return entityconverter(id,str) end + -- end return xml.convert(data,settings) end function lxml.load(id,filename,compress,entities) - filename = commands.preparedfile(filename) + filename = commands.preparedfile(filename) -- not commands! if trace_loading then report_lxml("loading file '%s' as '%s'",filename,id) end @@ -407,12 +458,9 @@ function xml.getbuffer(name,compress,entities) -- we need to make sure that comm end function lxml.loadbuffer(id,name,compress,entities) - if not name or name == "" then - name = tex.jobname - end starttiming(xml) nofconverted = nofconverted + 1 - local data = buffers.getcontent(name or id) + local data = buffers.collectcontent(name or id) -- name can be list local xmltable = lxml.convert(id,data,compress,entities) lxml.store(id,xmltable) stoptiming(xml) @@ -469,10 +517,11 @@ local function tex_element(e,handlers) addindex(rootname,false,true) ix = e.ix end - texsprint(ctxcatcodes,"\\xmlw{",command,"}{",rootname,"::",ix,"}") + -- faster than context.xmlw + contextsprint(ctxcatcodes,"\\xmlw{",command,"}{",rootname,"::",ix,"}") else report_lxml( "fatal error: no index for '%s'",command) - texsprint(ctxcatcodes,"\\xmlw{",command,"}{",ix or 0,"}") + contextsprint(ctxcatcodes,"\\xmlw{",command,"}{",ix or 0,"}") end elseif tc == "function" then command(e) @@ -495,7 +544,7 @@ pihandlers[#pihandlers+1] = function(str) if str then local a, b, c, d = lpegmatch(parser,str) if d then - texsprint(ctxcatcodes,"\\xmlcontextdirective{",a",}{",b,"}{",c,"}{",d,"}") + contextsprint(ctxcatcodes,"\\xmlcontextdirective{",a,"}{",b,"}{",c,"}{",d,"}") end end end @@ -507,6 +556,16 @@ local function tex_pi(e,handlers) end end +local obeycdata = true + +function lxml.setcdata() + obeycdata = true +end + +function lxml.resetcdata() + obeycdata = false +end + local function tex_cdata(e,handlers) if obeycdata then toverbatim(e.dt[1]) @@ -514,16 +573,16 @@ local function tex_cdata(e,handlers) end local function tex_text(e) + e = xmlunprivatized(e) lpegmatch(xmltextcapture,e) end -local function ctx_text(e) +local function ctx_text(e) -- can be just context(e) as we split there lpegmatch(ctxtextcapture,e) end local function tex_handle(...) --- report_lxml( "error while flushing: %s", concat { ... }) - texsprint(...) -- notcatcodes is active anyway + contextsprint(ctxcatcodes,...) -- notcatcodes is active anyway end local xmltexhandler = xml.newhandlers { @@ -543,6 +602,62 @@ local xmltexhandler = xml.newhandlers { lxml.xmltexhandler = xmltexhandler +-- begin of test + +local function tex_space(e) + e = xmlunprivatized(e) + lpegmatch(xmlspacecapture,e) +end + +local xmltexspacehandler = xml.newhandlers { + name = "texspace", + handle = tex_handle, + functions = { + ["@dt@"] = tex_doctype, + ["@el@"] = tex_element, + ["@pi@"] = tex_pi, + ["@cm@"] = tex_comment, + ["@cd@"] = tex_cdata, + ["@tx@"] = tex_space, + } +} + +local function tex_line(e) + e = xmlunprivatized(e) + lpegmatch(xmllinecapture,e) +end + +local xmltexlinehandler = xml.newhandlers { + name = "texline", + handle = tex_handle, + functions = { + ["@dt@"] = tex_doctype, + ["@el@"] = tex_element, + ["@pi@"] = tex_pi, + ["@cm@"] = tex_comment, + ["@cd@"] = tex_cdata, + ["@tx@"] = tex_line, + } +} + +function lxml.flushspacewise(id) -- keeps spaces and lines + id = getid(id) + local dt = id and id.dt + if dt then + xmlserialize(dt,xmltexspacehandler) + end +end + +function lxml.flushlinewise(id) -- keeps lines + id = getid(id) + local dt = id and id.dt + if dt then + xmlserialize(dt,xmltexlinehandler) + end +end + +-- end of test + function lxml.serialize(root) xmlserialize(root,xmltexhandler) end @@ -550,22 +665,28 @@ end function lxml.setaction(id,pattern,action) local collected = xmlapplylpath(getid(id),pattern) if collected then - for c=1,#collected do - collected[c].command = action + local nc = #collected + if nc > 0 then + for c=1,nc do + collected[c].command = action + end end end end -local function sprint(root) +local function sprint(root) -- check rawroot usage if root then local tr = type(root) if tr == "string" then -- can also be result of lpath - -- rawroot = false + -- rawroot = false -- ? + root = xmlunprivatized(root) lpegmatch(xmltextcapture,root) elseif tr == "table" then if forceraw then rawroot = root - texwrite(xmltostring(root)) + -- contextsprint(ctxcatcodes,xmltostring(root)) -- goes wrong with % etc + root = xmlunprivatized(xmltostring(root)) + lpegmatch(xmltextcapture,root) -- goes to toc else xmlserialize(root,xmltexhandler) end @@ -585,6 +706,7 @@ local function tprint(root) -- we can move sprint inline end end elseif tr == "string" then + root = xmlunprivatized(root) lpegmatch(xmltextcapture,root) end end @@ -595,21 +717,24 @@ local function cprint(root) -- content -- quit elseif type(root) == 'string' then -- rawroot = false + root = xmlunprivatized(root) lpegmatch(xmltextcapture,root) else local rootdt = root.dt if forceraw then rawroot = root - texwrite(xmltostring(rootdt or root)) + -- contextsprint(ctxcatcodes,xmltostring(rootdt or root)) + root = xmlunprivatized(xmltostring(root)) + lpegmatch(xmltextcapture,root) -- goes to toc else xmlserialize(rootdt or root,xmltexhandler) end end end -xml.sprint = sprint local xmlsprint = sprint -- redo these names -xml.tprint = tprint local xmltprint = tprint -xml.cprint = cprint local xmlcprint = cprint +xml.sprint = sprint local xmlsprint = sprint -- calls ct mathml -> will be replaced +xml.tprint = tprint local xmltprint = tprint -- only used here +xml.cprint = cprint local xmlcprint = cprint -- calls ct mathml -> will be replaced -- now we can flush @@ -720,7 +845,7 @@ function lxml.flushsetups(id,...) if trace_loading then report_lxml("applying setup %02i = %s to %s",k,v,document) end - texsprint(ctxcatcodes,"\\xmlsetup{",id,"}{",v,"}") + contextsprint(ctxcatcodes,"\\xmlsetup{",id,"}{",v,"}") done[v] = true end end @@ -756,40 +881,45 @@ function lxml.setsetup(id,pattern,setup) if not setup or setup == "" or setup == "*" or setup == "-" or setup == "+" then local collected = xmlapplylpath(getid(id),pattern) if collected then - if trace_setups then - for c=1, #collected do - local e = collected[c] - local ix = e.ix or 0 - if setup == "-" then - e.command = false - report_lxml("lpath matched (a) %5i: %s = %s -> skipped",c,ix,setup) - elseif setup == "+" then - e.command = true - report_lxml("lpath matched (b) %5i: %s = %s -> text",c,ix,setup) - else - local tg = e.tg - if tg then -- to be sure - e.command = tg - local ns = e.rn or e.ns - if ns == "" then - report_lxml("lpath matched (c) %5i: %s = %s -> %s",c,ix,tg,tg) - else - report_lxml("lpath matched (d) %5i: %s = %s:%s -> %s",c,ix,ns,tg,tg) + local nc = #collected + if nc > 0 then + if trace_setups then + for c=1,nc do + local e = collected[c] + local ix = e.ix or 0 + if setup == "-" then + e.command = false + report_lxml("lpath matched (a) %5i: %s = %s -> skipped",c,ix,setup) + elseif setup == "+" then + e.command = true + report_lxml("lpath matched (b) %5i: %s = %s -> text",c,ix,setup) + else + local tg = e.tg + if tg then -- to be sure + e.command = tg + local ns = e.rn or e.ns + if ns == "" then + report_lxml("lpath matched (c) %5i: %s = %s -> %s",c,ix,tg,tg) + else + report_lxml("lpath matched (d) %5i: %s = %s:%s -> %s",c,ix,ns,tg,tg) + end end end end - end - else - for c=1, #collected do - local e = collected[c] - if setup == "-" then - e.command = false - elseif setup == "+" then - e.command = true - else - e.command = e.tg + else + for c=1,nc do + local e = collected[c] + if setup == "-" then + e.command = false + elseif setup == "+" then + e.command = true + else + e.command = e.tg + end end end + elseif trace_setups then + report_lxml("zero lpath matches for %s",pattern) end elseif trace_setups then report_lxml("no lpath matches for %s",pattern) @@ -799,44 +929,49 @@ function lxml.setsetup(id,pattern,setup) if a and b then local collected = xmlapplylpath(getid(id),pattern) if collected then - if trace_setups then - for c=1, #collected do - local e = collected[c] - local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0 - if b == "-" then - e.command = false - if ns == "" then - report_lxml("lpath matched (e) %5i: %s = %s -> skipped",c,ix,tg) + local nc = #collected + if nc > 0 then + if trace_setups then + for c=1,nc do + local e = collected[c] + local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0 + if b == "-" then + e.command = false + if ns == "" then + report_lxml("lpath matched (e) %5i: %s = %s -> skipped",c,ix,tg) + else + report_lxml("lpath matched (f) %5i: %s = %s:%s -> skipped",c,ix,ns,tg) + end + elseif b == "+" then + e.command = true + if ns == "" then + report_lxml("lpath matched (g) %5i: %s = %s -> text",c,ix,tg) + else + report_lxml("lpath matched (h) %5i: %s = %s:%s -> text",c,ix,ns,tg) + end else - report_lxml("lpath matched (f) %5i: %s = %s:%s -> skipped",c,ix,ns,tg) + e.command = a .. tg + if ns == "" then + report_lxml("lpath matched (i) %5i: %s = %s -> %s",c,ix,tg,e.command) + else + report_lxml("lpath matched (j) %5i: %s = %s:%s -> %s",c,ix,ns,tg,e.command) + end end - elseif b == "+" then - e.command = true - if ns == "" then - report_lxml("lpath matched (g) %5i: %s = %s -> text",c,ix,tg) - else - report_lxml("lpath matched (h) %5i: %s = %s:%s -> text",c,ix,ns,tg) - end - else - e.command = a .. tg - if ns == "" then - report_lxml("lpath matched (i) %5i: %s = %s -> %s",c,ix,tg,e.command) + end + else + for c=1,nc do + local e = collected[c] + if b == "-" then + e.command = false + elseif b == "+" then + e.command = true else - report_lxml("lpath matched (j) %5i: %s = %s:%s -> %s",c,ix,ns,tg,e.command) + e.command = a .. e.tg end end end - else - for c=1, #collected do - local e = collected[c] - if b == "-" then - e.command = false - elseif b == "+" then - e.command = true - else - e.command = a .. e.tg - end - end + elseif trace_setups then + report_lxml("zero lpath matches for %s",pattern) end elseif trace_setups then report_lxml("no lpath matches for %s",pattern) @@ -844,21 +979,26 @@ function lxml.setsetup(id,pattern,setup) else local collected = xmlapplylpath(getid(id),pattern) if collected then - if trace_setups then - for c=1, #collected do - local e = collected[c] - e.command = setup - local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0 - if ns == "" then - report_lxml("lpath matched (k) %5i: %s = %s -> %s",c,ix,tg,setup) - else - report_lxml("lpath matched (l) %5i: %s = %s:%s -> %s",c,ix,ns,tg,setup) + local nc = #collected + if nc > 0 then + if trace_setups then + for c=1,nc do + local e = collected[c] + e.command = setup + local ns, tg, ix = e.rn or e.ns, e.tg, e.ix or 0 + if ns == "" then + report_lxml("lpath matched (k) %5i: %s = %s -> %s",c,ix,tg,setup) + else + report_lxml("lpath matched (l) %5i: %s = %s:%s -> %s",c,ix,ns,tg,setup) + end + end + else + for c=1,nc do + collected[c].command = setup end end - else - for c=1, #collected do - collected[c].command = setup - end + elseif trace_setups then + report_lxml("zero lpath matches for %s",pattern) end elseif trace_setups then report_lxml("no lpath matches for %s",pattern) @@ -872,81 +1012,111 @@ end local finalizers = xml.finalizers.tex local function first(collected) - if collected then + if collected and #collected > 0 then xmlsprint(collected[1]) end end local function last(collected) if collected then - xmlsprint(collected[#collected]) + local nc = #collected + if nc > 0 then + xmlsprint(collected[nc]) + end end end local function all(collected) if collected then - for c=1,#collected do - xmlsprint(collected[c]) + local nc = #collected + if nc > 0 then + for c=1,nc do + xmlsprint(collected[c]) + end end end end local function reverse(collected) if collected then - for c=#collected,1,-1 do - xmlsprint(collected[c]) + local nc = #collected + if nc >0 then + for c=nc,1,-1 do + xmlsprint(collected[c]) + end end end end local function count(collected) - texwrite((collected and #collected) or 0) + contextsprint(ctxcatcodes,(collected and #collected) or 0) -- why ctxcatcodes end local function position(collected,n) -- todo: if not n then == match if collected then - n = tonumber(n) or 0 - if n < 0 then - n = #collected + n + 1 - end - if n > 0 then - xmlsprint(collected[n]) + local nc = #collected + if nc > 0 then + n = tonumber(n) or 0 + if n < 0 then + n = nc + n + 1 + end + if n > 0 then + local cn = collected[n] + if cn then + xmlsprint(cn) + return + end + end end end end local function match(collected) -- is match in preceding collected, never change, see bibxml local m = collected and collected[1] - texwrite(m and m.mi or 0) + contextsprint(ctxcatcodes,m and m.mi or 0) -- why ctxcatcodes end local function index(collected,n) if collected then - n = tonumber(n) or 0 - if n < 0 then - n = #collected + n + 1 - end - if n > 0 then - texwrite(collected[n].ni or 0) + local nc = #collected + if nc > 0 then + n = tonumber(n) or 0 + if n < 0 then + n = nc + n + 1 -- brrr + end + if n > 0 then + local cn = collected[n] + if cn then + contextsprint(ctxcatcodes,cn.ni or 0) -- why ctxcatcodes + return + end + end end end + contextsprint(ctxcatcodes,0) -- why ctxcatcodes end local function command(collected,cmd,otherwise) local n = collected and #collected if n and n > 0 then - for c=1,n do + local wildcard = find(cmd,"%*") + for c=1,n do -- maybe optimize for n=1 local e = collected[c] local ix = e.ix + local name = e.name if not ix then - lxml.addindex(e.name,false,true) + lxml.addindex(name,false,true) ix = e.ix end - texsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",e.name,"::",ix,"}") + if wildcard then + contextsprint(ctxcatcodes,"\\xmlw{",(gsub(cmd,"%*",e.tg)),"}{",name,"::",ix,"}") + else + contextsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",name,"::",ix,"}") + end end elseif otherwise then - texsprint(ctxcatcodes,"\\xmlw{",otherwise,"}{#1}") + contextsprint(ctxcatcodes,"\\xmlw{",otherwise,"}{#1}") end end @@ -955,22 +1125,22 @@ local function attribute(collected,a,default) local at = collected[1].at local str = (at and at[a]) or default if str and str ~= "" then - texsprint(notcatcodes,str) + contextsprint(notcatcodes,str) end elseif default then - texsprint(notcatcodes,default) + contextsprint(notcatcodes,default) end end local function chainattribute(collected,arguments) -- todo: optional levels - if collected then + if collected and #collected > 0 then local e = collected[1] while e do local at = e.at if at then local a = at[arguments] if a then - texsprint(notcatcodes,a) + contextsprint(notcatcodes,a) end else break -- error @@ -983,7 +1153,9 @@ end local function text(collected) if collected then local nc = #collected - if nc == 1 then -- hardly any gain so this will go + if nc == 0 then + -- nothing + elseif nc == 1 then -- hardly any gain so this will go cprint(collected[1]) else for c=1,nc do cprint(collected[c]) @@ -993,71 +1165,80 @@ end local function ctxtext(collected) if collected then - for c=1,#collected do - texsprint(ctxcatcodes,collected[1].dt) + local nc = #collected + if nc > 0 then + for c=1,nc do + contextsprint(ctxcatcodes,collected[c].dt) + end end end end ---~ local str = xmltext(getid(id),pattern) or "" ---~ str = gsub(str,"^%s*(.-)%s*$","%1") ---~ if nolines then ---~ str = gsub(str,"%s+"," ") ---~ end - local function stripped(collected) -- tricky as we strip in place if collected then - for c=1,#collected do - cprint(xml.stripelement(collected[c])) + local nc = #collected + if nc > 0 then + for c=1,nc do + cprint(xml.stripelement(collected[c])) + end end end end local function lower(collected) - if collected then - for c=1,#collected do - texsprint(ctxcatcodes,lowerchars(collected[1].dt[1])) + if not collected then + local nc = #collected + if nc > 0 then + for c=1,nc do + contextsprint(ctxcatcodes,lowerchars(collected[c].dt[1])) + end end end end local function upper(collected) if collected then - for c=1,#collected do - texsprint(ctxcatcodes,upperchars(collected[1].dt[1])) + local nc = #collected + if nc > 0 then + for c=1,nc do + contextsprint(ctxcatcodes,upperchars(collected[c].dt[1])) + end end end end local function number(collected) - if collected then - local n = 0 - for c=1,#collected do + local nc = collected and #collected or 0 + local n = 0 + if nc > 0 then + for c=1,nc do n = n + tonumber(collected[c].dt[1] or 0) end - texwrite(n) end + contextsprint(ctxcatcodes,n) end local function concatrange(collected,start,stop,separator,lastseparator,textonly) -- test this on mml if collected then local nofcollected = #collected - local separator = separator or "" - local lastseparator = lastseparator or separator or "" - start, stop = (start == "" and 1) or tonumber(start) or 1, (stop == "" and nofcollected) or tonumber(stop) or nofcollected - if stop < 0 then stop = nofcollected + stop end -- -1 == last-1 - for i=start,stop do - if textonly then - xmlcprint(collected[i]) - else - xmlsprint(collected[i]) - end - if i == nofcollected then - -- nothing - elseif i == nofcollected-1 and lastseparator ~= "" then - texsprint(ctxcatcodes,lastseparator) - elseif separator ~= "" then - texsprint(ctxcatcodes,separator) + if nofcollected > 0 then + local separator = separator or "" + local lastseparator = lastseparator or separator or "" + start, stop = (start == "" and 1) or tonumber(start) or 1, (stop == "" and nofcollected) or tonumber(stop) or nofcollected + if stop < 0 then stop = nofcollected + stop end -- -1 == last-1 + for i=start,stop do + if textonly then + xmlcprint(collected[i]) + else + xmlsprint(collected[i]) + end + if i == nofcollected then + -- nothing + elseif i == nofcollected-1 and lastseparator ~= "" then + contextsprint(ctxcatcodes,lastseparator) + elseif separator ~= "" then + contextsprint(ctxcatcodes,separator) + end end end end @@ -1090,37 +1271,44 @@ finalizers.default = all -- !! local concat = table.concat -function finalizers.tag(collected) +function finalizers.tag(collected,n) if collected then - local c - if n == 0 or not n then - c = collected[1] - elseif n > 1 then - c = collected[n] - else - c = collected[#collected-n+1] - end - if c then - texsprint(c.tg) + local nc = #collected + if nc > 0 then + n = tonumber(n) or 0 + local c + if n == 0 then + c = collected[1] + elseif n > 1 then + c = collected[n] + else + c = collected[nc-n+1] + end + if c then + contextsprint(ctxcatcodes,c.tg) + end end end end -function finalizers.name(collected) +function finalizers.name(collected,n) if collected then - local c - if n == 0 or not n then - c = collected[1] - elseif n > 1 then - c = collected[n] - else - c = collected[#collected-n+1] - end - if c then - if c.ns == "" then - texsprint(c.tg) + local nc = #collected + if nc > 0 then + local c + if n == 0 or not n then + c = collected[1] + elseif n > 1 then + c = collected[n] else - texsprint(c.ns,":",c.tg) + c = collected[nc-n+1] + end + if c then + if c.ns == "" then + contextsprint(ctxcatcodes,c.tg) + else + contextsprint(ctxcatcodes,c.ns,":",c.tg) + end end end end @@ -1128,13 +1316,16 @@ end function finalizers.tags(collected,nonamespace) if collected then - for c=1,#collected do - local e = collected[c] - local ns, tg = e.ns, e.tg - if nonamespace or ns == "" then - texsprint(tg) - else - texsprint(ns,":",tg) + local nc = #collected + if nc > 0 then + for c=1,nc do + local e = collected[c] + local ns, tg = e.ns, e.tg + if nonamespace or ns == "" then + contextsprint(ctxcatcodes,tg) + else + contextsprint(ctxcatcodes,ns,":",tg) + end end end end @@ -1145,14 +1336,17 @@ end local function verbatim(id,before,after) local root = getid(id) if root then - if before then texsprint(ctxcatcodes,before,"[",root.tg or "?","]") end + if before then contextsprint(ctxcatcodes,before,"[",root.tg or "?","]") end lxml.toverbatim(xmltostring(root.dt)) - if after then texsprint(ctxcatcodes,after) end +--~ lxml.toverbatim(xml.totext(root.dt)) + if after then contextsprint(ctxcatcodes,after) end end end + function lxml.inlineverbatim(id) verbatim(id,"\\startxmlinlineverbatim","\\stopxmlinlineverbatim") end + function lxml.displayverbatim(id) verbatim(id,"\\startxmldisplayverbatim","\\stopxmldisplayverbatim") end @@ -1196,27 +1390,40 @@ end function lxml.raw(id,pattern) -- the content, untouched by commands local collected = (pattern and xmlapplylpath(getid(id),pattern)) or getid(id) - if collected then - texsprint(xmltostring(collected[1].dt)) + if collected and #collected > 0 then + contextsprint(notcatcodes,xmltostring(collected[1].dt)) end end function lxml.context(id,pattern) -- the content, untouched by commands if not pattern then local collected = getid(id) - -- texsprint(ctxcatcodes,collected.dt[1]) ctx_text(collected.dt[1]) else local collected = xmlapplylpath(getid(id),pattern) or getid(id) if collected and #collected > 0 then - texsprint(ctxcatcodes,collected[1].dt) + contextsprint(ctxcatcodes,collected[1].dt) + end + end +end + +function lxml.context(id,pattern) -- the content, untouched by commands + if pattern then + local collected = xmlapplylpath(getid(id),pattern) or getid(id) + if collected and #collected > 0 then + contextsprint(ctxcatcodes,collected[1].dt) + end + else + local collected = getid(id) + if collected and #collected > 0 then + ctx_text(collected.dt[1]) end end end function lxml.text(id,pattern) local collected = (pattern and xmlapplylpath(getid(id),pattern)) or getid(id) - if collected then + if collected and #collected > 0 then text(collected) end end @@ -1224,17 +1431,11 @@ end lxml.content = text function lxml.position(id,pattern,n) - local collected = xmlapplylpath(getid(id),pattern) - if collected then - position(collected,n) - end + position(xmlapplylpath(getid(id),pattern),n) end function lxml.chainattribute(id,pattern,a,default) - local collected = xmlapplylpath(getid(id),pattern) - if collected then - chainattribute(collected,a,default) - end + chainattribute(xmlapplylpath(getid(id),pattern),a,default) end function lxml.concatrange(id,pattern,start,stop,separator,lastseparator,textonly) -- test this on mml @@ -1253,7 +1454,7 @@ lxml.index = lxml.position function lxml.pos(id) local root = getid(id) - texwrite((root and root.ni) or 0) + contextsprint(ctxcatcodes,(root and root.ni) or 0) end function lxml.att(id,a,default) @@ -1262,10 +1463,10 @@ function lxml.att(id,a,default) local at = root.at local str = (at and at[a]) or default if str and str ~= "" then - texsprint(notcatcodes,str) + contextsprint(notcatcodes,str) end elseif default then - texsprint(notcatcodes,default) + contextsprint(notcatcodes,default) end end @@ -1273,23 +1474,23 @@ function lxml.name(id) -- or remapped name? -> lxml.info, combine local r = getid(id) local ns = r.rn or r.ns or "" if ns ~= "" then - texsprint(ns,":",r.tg) + contextsprint(ctxcatcodes,ns,":",r.tg) else - texsprint(r.tg) + contextsprint(ctxcatcodes,r.tg) end end function lxml.match(id) -- or remapped name? -> lxml.info, combine - texsprint(getid(id).mi or 0) + contextsprint(ctxcatcodes,getid(id).mi or 0) end function lxml.tag(id) -- tag vs name -> also in l-xml tag->name - texsprint(getid(id).tg or "") + contextsprint(ctxcatcodes,getid(id).tg or "") end function lxml.namespace(id) -- or remapped name? local root = getid(id) - texsprint(root.rn or root.ns or "") + contextsprint(ctxcatcodes,root.rn or root.ns or "") end function lxml.flush(id) @@ -1318,15 +1519,18 @@ function lxml.command(id,pattern,cmd) local i, p = getid(id,true) local collected = xmlapplylpath(getid(i),pattern) if collected then - local rootname = p or i.name - for c=1,#collected do - local e = collected[c] - local ix = e.ix - if not ix then - addindex(rootname,false,true) - ix = e.ix + local nc = #collected + if nc > 0 then + local rootname = p or i.name + for c=1,nc do + local e = collected[c] + local ix = e.ix + if not ix then + addindex(rootname,false,true) + ix = e.ix + end + contextsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",rootname,"::",ix,"}") end - texsprint(ctxcatcodes,"\\xmlw{",cmd,"}{",rootname,"::",ix,"}") end end end @@ -1434,8 +1638,11 @@ lxml.get_id = getid lxml.obsolete.get_id = getid function xml.finalizers.tex.lettered(collected) if collected then - for c=1,#collected do - texsprint(ctxcatcodes,lettered(collected[1].dt[1])) + local nc = #collected + if nc > 0 then + for c=1,nc do + contextsprint(ctxcatcodes,lettered(collected[c].dt[1])) + end end end end @@ -1443,7 +1650,7 @@ end --~ function xml.finalizers.tex.apply(collected,what) -- to be tested --~ if collected then --~ for c=1,#collected do ---~ texsprint(ctxcatcodes,what(collected[1].dt[1])) +--~ contextsprint(ctxcatcodes,what(collected[c].dt[1])) --~ end --~ end --~ end |