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