1if not modules then modules = { } end modules ['lxml-aux'] = {
2 version = 1.001,
3 comment = "this module is the basis for the lxml-* ones",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12local trace_manipulations = false trackers.register("lxml.manipulations", function(v) trace_manipulations = v end)
13local trace_inclusions = false trackers.register("lxml.inclusions", function(v) trace_inclusions = v end)
14
15local report_xml = logs.reporter("xml")
16
17local xml = xml
18
19local xmlcopy, xmlname = xml.copy, xml.name
20local xmlinheritedconvert = xml.inheritedconvert
21local xmlapplylpath = xml.applylpath
22
23local type, next, setmetatable, getmetatable = type, next, setmetatable, getmetatable
24local insert, remove, fastcopy, concat = table.insert, table.remove, table.fastcopy, table.concat
25local gmatch, gsub, format, find, strip, match = string.gmatch, string.gsub, string.format, string.find, string.strip, string.match
26local utfbyte = utf.byte
27local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
28local striplinepatterns = utilities.strings.striplinepatterns
29
30local function report(what,pattern,c,e)
31 report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern)
32end
33
34local function withelements(e,handle,depth)
35 if e and handle then
36 local edt = e.dt
37 if edt then
38 depth = depth or 0
39 for i=1,#edt do
40 local e = edt[i]
41 if type(e) == "table" then
42 handle(e,depth)
43 withelements(e,handle,depth+1)
44 end
45 end
46 end
47 end
48end
49
50xml.withelements = withelements
51
52function xml.withelement(e,n,handle)
53 if e and n ~= 0 and handle then
54 local edt = e.dt
55 if edt then
56 if n > 0 then
57 for i=1,#edt do
58 local ei = edt[i]
59 if type(ei) == "table" then
60 if n == 1 then
61 handle(ei)
62 return
63 else
64 n = n - 1
65 end
66 end
67 end
68 elseif n < 0 then
69 for i=#edt,1,-1 do
70 local ei = edt[i]
71 if type(ei) == "table" then
72 if n == -1 then
73 handle(ei)
74 return
75 else
76 n = n + 1
77 end
78 end
79 end
80 end
81 end
82 end
83end
84
85function xml.each(root,pattern,handle,reverse)
86 local collected = xmlapplylpath(root,pattern)
87 if collected then
88 if handle then
89 if reverse then
90 for c=#collected,1,-1 do
91 handle(collected[c])
92 end
93 else
94 for c=1,#collected do
95 handle(collected[c])
96 end
97 end
98 end
99 return collected
100 end
101end
102
103function xml.processattributes(root,pattern,handle)
104 local collected = xmlapplylpath(root,pattern)
105 if collected and handle then
106 for c=1,#collected do
107 handle(collected[c].at)
108 end
109 end
110 return collected
111end
112
113
114
115function xml.collect(root, pattern)
116 return xmlapplylpath(root,pattern)
117end
118
119function xml.collecttexts(root, pattern, flatten)
120 local collected = xmlapplylpath(root,pattern)
121 if collected and flatten then
122 local xmltostring = xml.tostring
123 for c=1,#collected do
124 collected[c] = xmltostring(collected[c].dt)
125 end
126 end
127 return collected or { }
128end
129
130function xml.collect_tags(root, pattern, nonamespace)
131 local collected = xmlapplylpath(root,pattern)
132 if collected then
133 local t = { }
134 local n = 0
135 for c=1,#collected do
136 local e = collected[c]
137 local ns = e.ns
138 local tg = e.tg
139 n = n + 1
140 if nonamespace then
141 t[n] = tg
142 elseif ns == "" then
143 t[n] = tg
144 else
145 t[n] = ns .. ":" .. tg
146 end
147 end
148 return t
149 end
150end
151
152
153
154local no_root = { no_root = true }
155
156local function redo_ni(d)
157 for k=1,#d do
158 local dk = d[k]
159 if type(dk) == "table" then
160 dk.ni = k
161 end
162 end
163end
164
165xml.reindex = redo_ni
166
167local function xmltoelement(whatever,root)
168 if not whatever then
169 return nil
170 end
171 local element
172 if type(whatever) == "string" then
173 element = xmlinheritedconvert(whatever,root,true)
174 else
175 element = whatever
176 end
177 if element.error then
178 return whatever
179 end
180 if element then
181
182
183
184
185
186 end
187 return element
188end
189
190xml.toelement = xmltoelement
191
192
193
194
195
196
197
198
199
200
201
202local function copiedelement(element,newparent)
203 if type(element) ~= "string" then
204 element = xmlcopy(element).dt
205 if newparent and type(element) == "table" then
206 for i=1,#element do
207 local e = element[i]
208 if type(e) == "table" then
209 e.__p__ = newparent
210 end
211 end
212 end
213 end
214 return element
215end
216
217function xml.delete(root,pattern)
218 if not pattern or pattern == "" then
219 local p = root.__p__
220 if p then
221 if trace_manipulations then
222 report('deleting',"--",c,root)
223 end
224 local d = p.dt
225 remove(d,root.ni)
226 redo_ni(d)
227 end
228 else
229 local collected = xmlapplylpath(root,pattern)
230 if collected then
231 for c=1,#collected do
232 local e = collected[c]
233 local p = e.__p__
234 if p then
235 if trace_manipulations then
236 report('deleting',pattern,c,e)
237 end
238 local d = p.dt
239 local ni = e.ni
240 if ni <= #d then
241 if false then
242 p.dt[ni] = ""
243 else
244
245 remove(d,ni)
246 redo_ni(d)
247 end
248 else
249
250 end
251 end
252 end
253 end
254 end
255end
256
257function xml.wipe(root,pattern)
258 local collected = xmlapplylpath(root,pattern)
259 if collected then
260 for c=1,#collected do
261 local e = collected[c]
262 local p = e.__p__
263 if p then
264 local d = p.dt
265 local ni = e.ni
266 if ni <= #d then
267 local dt = e.dt
268 if #dt == 1 then
269 local d1 = dt[1]
270 if type(d1) == "string" and match(d1,"^%s*$") then
271 if trace_manipulations then
272 report('wiping',pattern,c,e)
273 end
274 remove(d,ni)
275 redo_ni(d)
276 end
277 end
278 end
279 end
280 end
281 end
282end
283
284function xml.replace(root,pattern,whatever)
285 local element = root and xmltoelement(whatever,root)
286 local collected = element and xmlapplylpath(root,pattern)
287 if collected then
288 for c=1,#collected do
289 local e = collected[c]
290 local p = e.__p__
291 if p then
292 if trace_manipulations then
293 report('replacing',pattern,c,e)
294 end
295 local d = p.dt
296 local n = e.ni
297 local t = copiedelement(element,p)
298 if type(t) == "table" then
299 d[n] = t[1]
300 for i=2,#t do
301 n = n + 1
302 insert(d,n,t[i])
303 end
304 else
305 d[n] = t
306 end
307 redo_ni(d)
308 end
309 end
310 end
311end
312
313function xml.expand(root,pattern,whatever)
314 local collected = root and xmlapplylpath(root,pattern)
315 if collected then
316 for c=1,#collected do
317 local e = collected[c]
318 local p = e.__p__
319 if p then
320 if trace_manipulations then
321 report('expanding',pattern,c,e)
322 end
323 local d = p.dt
324 local n = e.ni
325 local t = whatever(e,p)
326 if t then
327 if type(t) == "table" then
328 t = xmlcopy(t)
329 d[n] = t[1]
330 for i=2,#t do
331 n = n + 1
332 insert(d,n,t[i])
333 end
334 else
335 d[n] = t
336 end
337 redo_ni(d)
338 end
339 end
340 end
341 end
342end
343
344local function wrap(e,wrapper)
345 local t = {
346 rn = e.rn,
347 tg = e.tg,
348 ns = e.ns,
349 at = e.at,
350 dt = e.dt,
351 __p__ = e,
352 }
353 setmetatable(t,getmetatable(e))
354 e.rn = wrapper.rn or e.rn or ""
355 e.tg = wrapper.tg or e.tg or ""
356 e.ns = wrapper.ns or e.ns or ""
357 e.at = fastcopy(wrapper.at)
358 e.dt = { t }
359end
360
361function xml.wrap(root,pattern,whatever)
362 if whatever then
363 local wrapper = xmltoelement(whatever,root)
364 local collected = xmlapplylpath(root,pattern)
365 if collected then
366 for c=1,#collected do
367 local e = collected[c]
368 if trace_manipulations then
369 report('wrapping',pattern,c,e)
370 end
371 wrap(e,wrapper)
372 end
373 end
374 else
375 wrap(root,xmltoelement(pattern))
376 end
377end
378
379local function inject_element(root,pattern,whatever,prepend)
380 local element = root and xmltoelement(whatever,root)
381 local collected = element and xmlapplylpath(root,pattern)
382 local function inject_e(e)
383 local r = e.__p__
384 local d = r.dt
385 local k = e.ni
386 local rri = r.ri
387 local edt = (rri and d[rri].dt) or (d and d[k] and d[k].dt)
388 if edt then
389 local be, af
390 local cp = copiedelement(element,e)
391 if prepend then
392 be, af = cp, edt
393 else
394 be, af = edt, cp
395 end
396 local bn = #be
397 for i=1,#af do
398 bn = bn + 1
399 be[bn] = af[i]
400 end
401 if rri then
402 r.dt[rri].dt = be
403 else
404 d[k].dt = be
405 end
406 redo_ni(d)
407 end
408 end
409 if not collected then
410
411 elseif collected.tg then
412
413 inject_e(collected)
414 else
415 for c=1,#collected do
416 inject_e(collected[c])
417 end
418 end
419end
420
421local function insert_element(root,pattern,whatever,before)
422 local element = root and xmltoelement(whatever,root)
423 local collected = element and xmlapplylpath(root,pattern)
424 local function insert_e(e)
425 local r = e.__p__
426 local d = r.dt
427 local k = e.ni
428 if not before then
429 k = k + 1
430 end
431 insert(d,k,copiedelement(element,r))
432 redo_ni(d)
433 end
434 if not collected then
435
436 elseif collected.tg then
437
438 insert_e(collected)
439 else
440 for c=1,#collected do
441 insert_e(collected[c])
442 end
443 end
444end
445
446xml.insert_element = insert_element
447xml.insertafter = insert_element
448xml.insertbefore = function(r,p,e) insert_element(r,p,e,true) end
449xml.injectafter = inject_element
450xml.injectbefore = function(r,p,e) inject_element(r,p,e,true) end
451
452
453
454local function include(xmldata,pattern,attribute,recursive,loaddata,level)
455
456 pattern = pattern or 'include'
457 loaddata = loaddata or io.loaddata
458 local collected = xmlapplylpath(xmldata,pattern)
459 if collected then
460 if not level then
461 level = 1
462 end
463 for c=1,#collected do
464 local ek = collected[c]
465 local name = nil
466 local ekdt = ek.dt
467 if ekdt then
468 local ekat = ek.at
469 local ekrt = ek.__p__
470 if ekrt then
471 local epdt = ekrt.dt
472 if not attribute or attribute == "" then
473 name = (type(ekdt) == "table" and ekdt[1]) or ekdt
474 end
475 if not name then
476 for a in gmatch(attribute or "href","([^|]+)") do
477 name = ekat[a]
478 if name then
479 break
480 end
481 end
482 end
483 local data = nil
484 if name and name ~= "" then
485 local d, n = loaddata(name)
486 data = d or ""
487 name = n or name
488 if trace_inclusions then
489 report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ")
490 end
491 end
492 if not data or data == "" then
493 epdt[ek.ni] = ""
494 elseif ekat["parse"] == "text" then
495
496 epdt[ek.ni] = xml.escaped(data)
497 else
498 local settings = xmldata.settings
499 local savedresource = settings.currentresource
500 settings.currentresource = name
501 local xi = xmlinheritedconvert(data,xmldata,true)
502 if not xi then
503 epdt[ek.ni] = ""
504 else
505 if recursive then
506 include(xi,pattern,attribute,recursive,loaddata,level+1)
507 end
508 local child = xml.body(xi)
509 child.__p__ = ekrt
510 child.__f__ = name
511 child.cf = name
512 epdt[ek.ni] = child
513 local settings = xmldata.settings
514 local inclusions = settings and settings.inclusions
515 if inclusions then
516 inclusions[#inclusions+1] = name
517 elseif settings then
518 settings.inclusions = { name }
519 else
520 settings = { inclusions = { name } }
521 xmldata.settings = settings
522 end
523 if child.er then
524 local badinclusions = settings.badinclusions
525 if badinclusions then
526 badinclusions[#badinclusions+1] = name
527 else
528 settings.badinclusions = { name }
529 end
530 end
531 end
532settings.currentresource = savedresource
533 end
534 end
535 end
536 end
537 end
538end
539
540xml.include = include
541
542function xml.inclusion(e,default)
543 while e do
544 local f = e.__f__
545 if f then
546 return f
547 else
548 e = e.__p__
549 end
550 end
551 return default
552end
553
554local function getinclusions(key,e,sorted)
555 while e do
556 local settings = e.settings
557 if settings then
558 local inclusions = settings[key]
559 if inclusions then
560 inclusions = table.unique(inclusions)
561 if sorted then
562 table.sort(inclusions)
563 end
564 return inclusions
565 else
566 e = e.__p__
567 end
568 else
569 e = e.__p__
570 end
571 end
572end
573
574function xml.inclusions(e,sorted)
575 return getinclusions("inclusions",e,sorted)
576end
577
578function xml.badinclusions(e,sorted)
579 return getinclusions("badinclusions",e,sorted)
580end
581
582local b_collapser = lpegpatterns.b_collapser
583local m_collapser = lpegpatterns.m_collapser
584local e_collapser = lpegpatterns.e_collapser
585local x_collapser = lpegpatterns.x_collapser
586
587local b_stripper = lpegpatterns.b_stripper
588local m_stripper = lpegpatterns.m_stripper
589local e_stripper = lpegpatterns.e_stripper
590local x_stripper = lpegpatterns.x_stripper
591
592local function stripelement(e,nolines,anywhere,everything)
593 local edt = e.dt
594 if edt then
595 local n = #edt
596 if n == 0 then
597 return e
598 elseif everything then
599 local t = { }
600 local m = 0
601 for i=1,n do
602 local str = edt[i]
603 if type(str) ~= "string" then
604 m = m + 1
605 t[m] = str
606 elseif str ~= "" then
607 str = lpegmatch(x_collapser,str)
608 if str ~= "" then
609 m = m + 1
610 t[m] = str
611 end
612 end
613 end
614 e.dt = t
615 elseif anywhere then
616 local t = { }
617 local m = 0
618 for i=1,n do
619 local str = edt[i]
620 if type(str) ~= "string" then
621 m = m + 1
622 t[m] = str
623 elseif str ~= "" then
624 if nolines then
625 str = lpegmatch((i == 1 and b_collapser) or (i == m and e_collapser) or m_collapser,str)
626 else
627 str = lpegmatch((i == 1 and b_stripper) or (i == m and e_stripper) or m_stripper,str)
628 end
629 if str ~= "" then
630 m = m + 1
631 t[m] = str
632 end
633 end
634 end
635 e.dt = t
636 else
637 local str = edt[1]
638 if type(str) == "string" then
639 if str ~= "" then
640 str = lpegmatch(nolines and b_collapser or b_stripper,str)
641 end
642 if str == "" then
643 remove(edt,1)
644 n = n - 1
645 else
646 edt[1] = str
647 end
648 end
649 if n > 0 then
650 str = edt[n]
651 if type(str) == "string" then
652 if str == "" then
653 remove(edt)
654 else
655 str = lpegmatch(nolines and e_collapser or e_stripper,str)
656 if str == "" then
657 remove(edt)
658 else
659 edt[n] = str
660 end
661 end
662 end
663 end
664 end
665 end
666 return e
667end
668
669xml.stripelement = stripelement
670
671function xml.strip(root,pattern,nolines,anywhere,everything)
672 local collected = xmlapplylpath(root,pattern)
673 if collected then
674 for i=1,#collected do
675 stripelement(collected[i],nolines,anywhere,everything)
676 end
677 end
678
679end
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701local function compactelement(e)
702 local edt = e.dt
703 if edt then
704 for e=1,#edt do
705 local str = edt[e]
706 if type(str) == "string" and not find(str,"%S") then
707 edt[e] = ""
708 end
709 end
710 end
711 return e
712end
713
714xml.compactelement = compactelement
715
716local function renamespace(root, oldspace, newspace)
717 local ndt = #root.dt
718 for i=1,ndt or 0 do
719 local e = root[i]
720 if type(e) == "table" then
721 if e.ns == oldspace then
722 e.ns = newspace
723 if e.rn then
724 e.rn = newspace
725 end
726 end
727 local edt = e.dt
728 if edt then
729 renamespace(edt, oldspace, newspace)
730 end
731 end
732 end
733end
734
735xml.renamespace = renamespace
736
737function xml.remaptag(root, pattern, newtg)
738 local collected = xmlapplylpath(root,pattern)
739 if collected then
740 for c=1,#collected do
741 collected[c].tg = newtg
742 end
743 end
744end
745
746function xml.remapnamespace(root, pattern, newns)
747 local collected = xmlapplylpath(root,pattern)
748 if collected then
749 for c=1,#collected do
750 collected[c].ns = newns
751 end
752 end
753end
754
755function xml.checknamespace(root, pattern, newns)
756 local collected = xmlapplylpath(root,pattern)
757 if collected then
758 for c=1,#collected do
759 local e = collected[c]
760 if (not e.rn or e.rn == "") and e.ns == "" then
761 e.rn = newns
762 end
763 end
764 end
765end
766
767function xml.remapname(root, pattern, newtg, newns, newrn)
768 local collected = xmlapplylpath(root,pattern)
769 if collected then
770 for c=1,#collected do
771 local e = collected[c]
772 e.tg, e.ns, e.rn = newtg, newns, newrn
773 end
774 end
775end
776
777
778
779function xml.cdatatotext(e)
780 local dt = e.dt
781 if #dt == 1 then
782 local first = dt[1]
783 if first.tg == "@cd@" then
784 e.dt = first.dt
785 end
786 else
787
788 end
789end
790
791
792
793
794
795function xml.texttocdata(e)
796 local dt = e.dt
797 local s = xml.tostring(dt)
798 e.tg = "@cd@"
799 e.special = true
800 e.ns = ""
801 e.rn = ""
802 e.dt = { s }
803 e.at = nil
804end
805
806
807
808
809
810function xml.elementtocdata(e)
811 local dt = e.dt
812 local s = xml.tostring(e)
813 e.tg = "@cd@"
814 e.special = true
815 e.ns = ""
816 e.rn = ""
817 e.dt = { s }
818 e.at = nil
819end
820
821xml.builtinentities = table.tohash { "amp", "quot", "apos", "lt", "gt" }
822
823local entities = characters and characters.entities or nil
824local builtinentities = xml.builtinentities
825
826function xml.addentitiesdoctype(root,option)
827 if not entities then
828 require("char-ent")
829 entities = characters.entities
830 end
831 if entities and root and root.tg == "@rt@" and root.statistics then
832 local list = { }
833 local hexify = option == "hexadecimal"
834 for k, v in table.sortedhash(root.statistics.entities.names) do
835 if not builtinentities[k] then
836 local e = entities[k]
837 if not e then
838 e = format("[%s]",k)
839 elseif hexify then
840 e = format("&#%05X;",utfbyte(k))
841 end
842 list[#list+1] = format(" <!ENTITY %s %q >",k,e)
843 end
844 end
845 local dt = root.dt
846 local n = dt[1].tg == "@pi@" and 2 or 1
847 if #list > 0 then
848 insert(dt, n, { "\n" })
849 insert(dt, n, {
850 tg = "@dt@",
851 dt = { format("Something [\n%s\n] ",concat(list)) },
852 ns = "",
853 special = true,
854 })
855 insert(dt, n, { "\n\n" })
856 else
857
858 end
859 end
860end
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876xml.all = xml.each
877xml.insert = xml.insertafter
878xml.inject = xml.injectafter
879xml.after = xml.insertafter
880xml.before = xml.insertbefore
881xml.process = xml.each
882
883
884
885xml.obsolete = xml.obsolete or { }
886local obsolete = xml.obsolete
887
888xml.strip_whitespace = xml.strip obsolete.strip_whitespace = xml.strip
889xml.collect_elements = xml.collect obsolete.collect_elements = xml.collect
890xml.delete_element = xml.delete obsolete.delete_element = xml.delete
891xml.replace_element = xml.replace obsolete.replace_element = xml.replace
892xml.each_element = xml.each obsolete.each_element = xml.each
893xml.process_elements = xml.process obsolete.process_elements = xml.process
894xml.insert_element_after = xml.insertafter obsolete.insert_element_after = xml.insertafter
895xml.insert_element_before = xml.insertbefore obsolete.insert_element_before = xml.insertbefore
896xml.inject_element_after = xml.injectafter obsolete.inject_element_after = xml.injectafter
897xml.inject_element_before = xml.injectbefore obsolete.inject_element_before = xml.injectbefore
898xml.process_attributes = xml.processattributes obsolete.process_attributes = xml.processattributes
899xml.collect_texts = xml.collecttexts obsolete.collect_texts = xml.collecttexts
900xml.inject_element = xml.inject obsolete.inject_element = xml.inject
901xml.remap_tag = xml.remaptag obsolete.remap_tag = xml.remaptag
902xml.remap_name = xml.remapname obsolete.remap_name = xml.remapname
903xml.remap_namespace = xml.remapnamespace obsolete.remap_namespace = xml.remapnamespace
904
905
906
907function xml.cdata(e)
908 if e then
909 local dt = e.dt
910 if dt and #dt == 1 then
911 local first = dt[1]
912 return first.tg == "@cd@" and first.dt[1] or ""
913 end
914 end
915 return ""
916end
917
918function xml.finalizers.xml.cdata(collected)
919 if collected then
920 local e = collected[1]
921 if e then
922 local dt = e.dt
923 if dt and #dt == 1 then
924 local first = dt[1]
925 return first.tg == "@cd@" and first.dt[1] or ""
926 end
927 end
928 end
929 return ""
930end
931
932function xml.insertcomment(e,str,n)
933 insert(e.dt,n or 1,{
934 tg = "@cm@",
935 ns = "",
936 special = true,
937 at = { },
938 dt = { str },
939 })
940end
941
942function xml.insertcdata(e,str,n)
943 insert(e.dt,n or 1,{
944 tg = "@cd@",
945 ns = "",
946 special = true,
947 at = { },
948 dt = { str },
949 })
950end
951
952function xml.setcomment(e,str,n)
953 e.dt = { {
954 tg = "@cm@",
955 ns = "",
956 special = true,
957 at = { },
958 dt = { str },
959 } }
960end
961
962function xml.setcdata(e,str)
963 e.dt = { {
964 tg = "@cd@",
965 ns = "",
966 special = true,
967 at = { },
968 dt = { str },
969 } }
970end
971
972
973
974function xml.separate(x,pattern)
975 local collected = xmlapplylpath(x,pattern)
976 if collected then
977 for c=1,#collected do
978 local e = collected[c]
979 local d = e.dt
980 if d == x then
981 report_xml("warning: xml.separate changes root")
982 x = d
983 end
984 local t = { "\n" }
985 local n = 1
986 local i = 1
987 local nd = #d
988 while i <= nd do
989 while i <= nd do
990 local di = d[i]
991 if type(di) == "string" then
992 if di == "\n" or find(di,"^%s+$") then
993 i = i + 1
994 else
995 d[i] = strip(di)
996 break
997 end
998 else
999 break
1000 end
1001 end
1002 if i > nd then
1003 break
1004 end
1005 t[n+1] = "\n"
1006 t[n+2] = d[i]
1007 t[n+3] = "\n"
1008 n = n + 3
1009 i = i + 1
1010 end
1011 t[n+1] = "\n"
1012 setmetatable(t,getmetatable(d))
1013 e.dt = t
1014 end
1015 end
1016 return x
1017end
1018
1019
1020
1021local helpers = xml.helpers or { }
1022xml.helpers = helpers
1023
1024local function normal(e,action)
1025 local edt = e.dt
1026 if edt then
1027 for i=1,#edt do
1028 local str = edt[i]
1029 if type(str) == "string" and str ~= "" then
1030 edt[i] = action(str)
1031 end
1032 end
1033 end
1034end
1035
1036local function recurse(e,action)
1037 local edt = e.dt
1038 if edt then
1039 for i=1,#edt do
1040 local str = edt[i]
1041 if type(str) ~= "string" then
1042 recurse(str,action)
1043 elseif str ~= "" then
1044 edt[i] = action(str)
1045 end
1046 end
1047 end
1048end
1049
1050function helpers.recursetext(collected,action,recursive)
1051 if recursive then
1052 for i=1,#collected do
1053 recurse(collected[i],action)
1054 end
1055 else
1056 for i=1,#collected do
1057 normal(collected[i],action)
1058 end
1059 end
1060end
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086local specials = {
1087 ["@rt@"] = "root",
1088 ["@pi@"] = "instruction",
1089 ["@cm@"] = "comment",
1090 ["@dt@"] = "declaration",
1091 ["@cd@"] = "cdata",
1092}
1093
1094local function convert(x,strip,flat)
1095 local ns = x.ns
1096 local tg = x.tg
1097 local at = x.at
1098 local dt = x.dt
1099 local node = flat and {
1100 [0] = (not x.special and (ns ~= "" and ns .. ":" .. tg or tg)) or nil,
1101 } or {
1102 _namespace = ns ~= "" and ns or nil,
1103 _tag = not x.special and tg or nil,
1104 _type = specials[tg] or "_element",
1105 }
1106 if at then
1107 for k, v in next, at do
1108 node[k] = v
1109 end
1110 end
1111 local n = 0
1112 for i=1,#dt do
1113 local di = dt[i]
1114 if type(di) == "table" then
1115 if flat and di.special then
1116
1117 else
1118 di = convert(di,strip,flat)
1119 if di then
1120 n = n + 1
1121 node[n] = di
1122 end
1123 end
1124 elseif strip then
1125 di = lpegmatch(strip,di)
1126 if di ~= "" then
1127 n = n + 1
1128 node[n] = di
1129 end
1130 else
1131 n = n + 1
1132 node[n] = di
1133 end
1134 end
1135 if next(node) then
1136 return node
1137 end
1138end
1139
1140function xml.totable(x,strip,flat)
1141 if type(x) == "table" then
1142 if strip then
1143 strip = striplinepatterns[strip]
1144 end
1145 return convert(x,strip,flat)
1146 end
1147end
1148
1149
1150
1151
1152
1153function xml.rename(e,namespace,name,attributes)
1154 if type(e) ~= "table" or not e.tg then
1155 return
1156 end
1157 if type(name) == "table" then
1158 attributes = name
1159 name = namespace
1160 namespace = ""
1161 elseif type(name) ~= "string" then
1162 attributes = { }
1163 name = namespace
1164 namespace = ""
1165 end
1166 if type(attributes) ~= "table" then
1167 attributes = { }
1168 end
1169 e.ns = namespace
1170 e.rn = namespace
1171 e.tg = name
1172 e.at = attributes
1173end
1174 |