lxml-aux.lua /size: 31 Kb    last modification: 2020-07-01 14:35
1
if
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
-- not all functions here make sense anymore vbut we keep them for
10
-- compatibility reasons
11 12
local
trace_manipulations
=
false
trackers
.
register
(
"
lxml.manipulations
"
,
function
(
v
)
trace_manipulations
=
v
end
)
13
local
trace_inclusions
=
false
trackers
.
register
(
"
lxml.inclusions
"
,
function
(
v
)
trace_inclusions
=
v
end
)
14 15
local
report_xml
=
logs
.
reporter
(
"
xml
"
)
16 17
local
xml
=
xml
18 19
local
xmlcopy
,
xmlname
=
xml
.
copy
,
xml
.
name
20
local
xmlinheritedconvert
=
xml
.
inheritedconvert
21
local
xmlapplylpath
=
xml
.
applylpath
22 23
local
type
,
next
,
setmetatable
,
getmetatable
=
type
,
next
,
setmetatable
,
getmetatable
24
local
insert
,
remove
,
fastcopy
,
concat
=
table
.
insert
,
table
.
remove
,
table
.
fastcopy
,
table
.
concat
25
local
gmatch
,
gsub
,
format
,
find
,
strip
,
match
=
string
.
gmatch
,
string
.
gsub
,
string
.
format
,
string
.
find
,
string
.
strip
,
string
.
match
26
local
utfbyte
=
utf
.
byte
27
local
lpegmatch
,
lpegpatterns
=
lpeg
.
match
,
lpeg
.
patterns
28
local
striplinepatterns
=
utilities
.
strings
.
striplinepatterns
29 30
local
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
)
32
end
33 34
local
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
48
end
49 50
xml
.
withelements
=
withelements
51 52
function
xml
.
withelement
(
e
,
n
,
handle
)
-- slow
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
83
end
84 85
function
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
101
end
102 103
function
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
111
end
112 113
--[[ldx-- 114<p>The following functions collect elements and texts.</p> 115--ldx]]
--
116 117
-- are these still needed -> lxml-cmp.lua
118 119
function
xml
.
collect
(
root
,
pattern
)
120
return
xmlapplylpath
(
root
,
pattern
)
121
end
122 123
function
xml
.
collecttexts
(
root
,
pattern
,
flatten
)
-- todo: variant with handle
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
{
}
132
end
133 134
function
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
154
end
155 156
--[[ldx-- 157<p>We've now arrived at the functions that manipulate the tree.</p> 158--ldx]]
--
159 160
local
no_root
=
{
no_root
=
true
}
161 162
local
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
169
end
170 171
xml
.
reindex
=
redo_ni
172 173
local
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
)
-- beware, not really a root
180
else
181
element
=
whatever
-- we assume a table
182
end
183
if
element
.
error
then
184
return
whatever
-- string
185
end
186
if
element
then
187
--~ if element.ri then
188
--~ element = element.dt[element.ri].dt
189
--~ else
190
--~ element = element.dt
191
--~ end
192
end
193
return
element
194
end
195 196
xml
.
toelement
=
xmltoelement
197 198
local
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
208
end
209 210
function
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
)
-- can be made faster and inlined
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
-- what if multiple deleted in one set
238
remove
(
d
,
ni
)
239
redo_ni
(
d
)
-- can be made faster and inlined
240
end
241
else
242
-- disturbing
243
end
244
end
245
end
246
end
247
end
248
end
249 250
function
xml
.
wipe
(
root
,
pattern
)
-- not yet in manual
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
)
-- can be made faster and inlined
269
end
270
end
271
end
272
end
273
end
274
end
275
end
276 277
function
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
)
-- probably not needed
301
end
302
end
303
end
304
end
305 306
local
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
}
321
end
322 323
function
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
339
end
340 341
local
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
-- nothing
373
elseif
collected
.
tg
then
374
-- first or so
375
inject_e
(
collected
)
376
else
377
for
c
=
1
,
#
collected
do
378
inject_e
(
collected
[
c
]
)
379
end
380
end
381
end
382 383
local
function
insert_element
(
root
,
pattern
,
whatever
,
before
)
-- todo: element als functie
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
-- nothing
398
elseif
collected
.
tg
then
399
-- first or so
400
insert_e
(
collected
)
401
else
402
for
c
=
1
,
#
collected
do
403
insert_e
(
collected
[
c
]
)
404
end
405
end
406
end
407 408
xml
.
insert_element
=
insert_element
409
xml
.
insertafter
=
insert_element
410
xml
.
insertbefore
=
function
(
r
,
p
,
e
)
insert_element
(
r
,
p
,
e
,
true
)
end
411
xml
.
injectafter
=
inject_element
412
xml
.
injectbefore
=
function
(
r
,
p
,
e
)
inject_element
(
r
,
p
,
e
,
true
)
end
413 414
-- loaddata can restrict loading
415 416
local
function
include
(
xmldata
,
pattern
,
attribute
,
recursive
,
loaddata
,
level
)
417
-- attribute = attribute or 'href'
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
-- check, probably always tab or str
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
]
=
"
"
-- xml.empty(d,k)
456
elseif
ekat
[
"
parse
"
]
=
=
"
text
"
then
457
-- for the moment hard coded
458
epdt
[
ek
.
ni
]
=
xml
.
escaped
(
data
)
-- d[k] = 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
]
=
"
"
-- xml.empty(d,k)
466
else
467
if
recursive
then
468
include
(
xi
,
pattern
,
attribute
,
recursive
,
loaddata
,
level
+
1
)
469
end
470
local
child
=
xml
.
body
(
xi
)
-- xml.assign(d,k,xi)
471
child
.
__p__
=
ekrt
472
child
.
__f__
=
name
-- handy for tracing
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
494
settings
.
currentresource
=
savedresource
495
end
496
end
497
end
498
end
499
end
500
end
501 502
xml
.
include
=
include
503 504
function
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
514
end
515 516
local
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
)
-- a copy
523
if
sorted
then
524
table
.
sort
(
inclusions
)
-- so we sort the copy
525
end
526
return
inclusions
-- and return the copy
527
else
528
e
=
e
.
__p__
529
end
530
else
531
e
=
e
.
__p__
532
end
533
end
534
end
535 536
function
xml
.
inclusions
(
e
,
sorted
)
537
return
getinclusions
(
"
inclusions
"
,
e
,
sorted
)
538
end
539 540
function
xml
.
badinclusions
(
e
,
sorted
)
541
return
getinclusions
(
"
badinclusions
"
,
e
,
sorted
)
542
end
543 544
local
b_collapser
=
lpegpatterns
.
b_collapser
545
local
m_collapser
=
lpegpatterns
.
m_collapser
546
local
e_collapser
=
lpegpatterns
.
e_collapser
547 548
local
b_stripper
=
lpegpatterns
.
b_stripper
549
local
m_stripper
=
lpegpatterns
.
m_stripper
550
local
e_stripper
=
lpegpatterns
.
e_stripper
551 552
local
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
-- convenient
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
-- convenient
610
end
611 612
xml
.
stripelement
=
stripelement
613 614
function
xml
.
strip
(
root
,
pattern
,
nolines
,
anywhere
)
-- strips all leading and trailing spacing
615
local
collected
=
xmlapplylpath
(
root
,
pattern
)
-- beware, indices no longer are valid now
616
if
collected
then
617
for
i
=
1
,
#
collected
do
618
stripelement
(
collected
[
i
]
,
nolines
,
anywhere
)
619
end
620
end
621
-- return root
622
end
623 624
-- local function compactelement(e)
625
-- local edt = e.dt
626
-- if edt then
627
-- local t = { }
628
-- local m = 0
629
-- for e=1,#edt do
630
-- local str = edt[e]
631
-- if type(str) ~= "string" then
632
-- m = m + 1
633
-- t[m] = str
634
-- elseif str ~= "" and find(str,"%S") then
635
-- m = m + 1
636
-- t[m] = str
637
-- end
638
-- end
639
-- e.dt = t
640
-- end
641
-- return e -- convenient
642
-- end
643 644
local
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
-- convenient
655
end
656 657
xml
.
compactelement
=
compactelement
658 659
local
function
renamespace
(
root
,
oldspace
,
newspace
)
-- fast variant
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
676
end
677 678
xml
.
renamespace
=
renamespace
679 680
function
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
687
end
688 689
function
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
696
end
697 698
function
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
708
end
709 710
function
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
718
end
719 720
--[[ldx-- 721<p>Helper (for q2p).</p> 722--ldx]]
--
723 724
function
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
-- maybe option
733
end
734
end
735 736
-- local x = xml.convert("<x><a>1<b>2</b>3</a></x>")
737
-- xml.texttocdata(xml.first(x,"a"))
738
-- print(x) -- <x><![CDATA[1<b>2</b>3]]></x>
739 740
function
xml
.
texttocdata
(
e
)
-- could be a finalizer
741
local
dt
=
e
.
dt
742
local
s
=
xml
.
tostring
(
dt
)
-- no shortcut?
743
e
.
tg
=
"
@cd@
"
744
e
.
special
=
true
745
e
.
ns
=
"
"
746
e
.
rn
=
"
"
747
e
.
dt
=
{
s
}
748
e
.
at
=
nil
749
end
750 751
-- local x = xml.convert("<x><a>1<b>2</b>3</a></x>")
752
-- xml.tocdata(xml.first(x,"a"))
753
-- print(x) -- <x><![CDATA[<a>1<b>2</b>3</a>]]></x>
754 755
function
xml
.
elementtocdata
(
e
)
-- could be a finalizer
756
local
dt
=
e
.
dt
757
local
s
=
xml
.
tostring
(
e
)
-- no shortcut?
758
e
.
tg
=
"
@cd@
"
759
e
.
special
=
true
760
e
.
ns
=
"
"
761
e
.
rn
=
"
"
762
e
.
dt
=
{
s
}
763
e
.
at
=
nil
764
end
765 766
xml
.
builtinentities
=
table
.
tohash
{
"
amp
"
,
"
quot
"
,
"
apos
"
,
"
lt
"
,
"
gt
"
}
-- used often so share
767 768
local
entities
=
characters
and
characters
.
entities
or
nil
769
local
builtinentities
=
xml
.
builtinentities
770 771
function
xml
.
addentitiesdoctype
(
root
,
option
)
-- we could also have a 'resolve' i.e. inline hex
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@
"
,
-- beware, doctype is unparsed
796
dt
=
{
format
(
"
Something [\n%s\n]
"
,
concat
(
list
)
)
}
,
797
ns
=
"
"
,
798
special
=
true
,
799
}
)
800
insert
(
dt
,
n
,
{
"
\n\n
"
}
)
801
else
802
-- insert(dt, n, { table.serialize(root.statistics) })
803
end
804
end
805
end
806 807
-- local str = [==[
808
-- <?xml version='1.0' standalone='yes' ?>
809
-- <root>
810
-- <a>test &nbsp; test &#123; test</a>
811
-- <b><![CDATA[oeps]]></b>
812
-- </root>
813
-- ]==]
814
--
815
-- local x = xml.convert(str)
816
-- xml.addentitiesdoctype(x,"hexadecimal")
817
-- print(x)
818 819
--[[ldx-- 820<p>Here are a few synonyms.</p> 821--ldx]]
--
822 823
xml
.
all
=
xml
.
each
824
xml
.
insert
=
xml
.
insertafter
825
xml
.
inject
=
xml
.
injectafter
826
xml
.
after
=
xml
.
insertafter
827
xml
.
before
=
xml
.
insertbefore
828
xml
.
process
=
xml
.
each
829 830
-- obsolete
831 832
xml
.
obsolete
=
xml
.
obsolete
or
{
}
833
local
obsolete
=
xml
.
obsolete
834 835
xml
.
strip_whitespace
=
xml
.
strip
obsolete
.
strip_whitespace
=
xml
.
strip
836
xml
.
collect_elements
=
xml
.
collect
obsolete
.
collect_elements
=
xml
.
collect
837
xml
.
delete_element
=
xml
.
delete
obsolete
.
delete_element
=
xml
.
delete
838
xml
.
replace_element
=
xml
.
replace
obsolete
.
replace_element
=
xml
.
replace
839
xml
.
each_element
=
xml
.
each
obsolete
.
each_element
=
xml
.
each
840
xml
.
process_elements
=
xml
.
process
obsolete
.
process_elements
=
xml
.
process
841
xml
.
insert_element_after
=
xml
.
insertafter
obsolete
.
insert_element_after
=
xml
.
insertafter
842
xml
.
insert_element_before
=
xml
.
insertbefore
obsolete
.
insert_element_before
=
xml
.
insertbefore
843
xml
.
inject_element_after
=
xml
.
injectafter
obsolete
.
inject_element_after
=
xml
.
injectafter
844
xml
.
inject_element_before
=
xml
.
injectbefore
obsolete
.
inject_element_before
=
xml
.
injectbefore
845
xml
.
process_attributes
=
xml
.
processattributes
obsolete
.
process_attributes
=
xml
.
processattributes
846
xml
.
collect_texts
=
xml
.
collecttexts
obsolete
.
collect_texts
=
xml
.
collecttexts
847
xml
.
inject_element
=
xml
.
inject
obsolete
.
inject_element
=
xml
.
inject
848
xml
.
remap_tag
=
xml
.
remaptag
obsolete
.
remap_tag
=
xml
.
remaptag
849
xml
.
remap_name
=
xml
.
remapname
obsolete
.
remap_name
=
xml
.
remapname
850
xml
.
remap_namespace
=
xml
.
remapnamespace
obsolete
.
remap_namespace
=
xml
.
remapnamespace
851 852
-- new (probably ok)
853 854
function
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
"
"
863
end
864 865
function
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
"
"
877
end
878 879
function
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
}
)
887
end
888 889
function
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
}
)
897
end
898 899
function
xml
.
setcomment
(
e
,
str
,
n
)
900
e
.
dt
=
{
{
901
tg
=
"
@cm@
"
,
902
ns
=
"
"
,
903
special
=
true
,
904
at
=
{
}
,
905
dt
=
{
str
}
,
906
}
}
907
end
908 909
function
xml
.
setcdata
(
e
,
str
)
910
e
.
dt
=
{
{
911
tg
=
"
@cd@
"
,
912
ns
=
"
"
,
913
special
=
true
,
914
at
=
{
}
,
915
dt
=
{
str
}
,
916
}
}
917
end
918 919
-- maybe helpers like this will move to an autoloader
920 921
function
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
-- first test is speedup
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
964
end
965 966
--
967 968
local
helpers
=
xml
.
helpers
or
{
}
969
xml
.
helpers
=
helpers
970 971
local
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
981
end
982 983
local
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
)
-- ,recursive
990
elseif
str
~
=
"
"
then
991
edt
[
i
]
=
action
(
str
)
992
end
993
end
994
end
995
end
996 997
function
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
1007
end
1008 1009
-- on request ... undocumented ...
1010
--
1011
-- _tag : element name
1012
-- _type : node type (_element can be an option)
1013
-- _namespace : only if given
1014
--
1015
-- [1..n] : text or table
1016
-- key : value or attribite 'key'
1017
--
1018
-- local str = [[
1019
-- <?xml version="1.0" ?>
1020
-- <a one="1">
1021
-- <!-- rubish -->
1022
-- <b two="1"/>
1023
-- <b two="2">
1024
-- c &gt; d
1025
-- </b>
1026
-- </a>
1027
-- ]]
1028
--
1029
-- inspect(xml.totable(xml.convert(str)))
1030
-- inspect(xml.totable(xml.convert(str),true))
1031
-- inspect(xml.totable(xml.convert(str),true,true))
1032 1033
local
specials
=
{
1034
[
"
@rt@
"
]
=
"
root
"
,
1035
[
"
@pi@
"
]
=
"
instruction
"
,
1036
[
"
@cm@
"
]
=
"
comment
"
,
1037
[
"
@dt@
"
]
=
"
declaration
"
,
1038
[
"
@cd@
"
]
=
"
cdata
"
,
1039
}
1040 1041
local
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
-- ignore
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
1085
end
1086 1087
function
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
1094
end
1095 1096
-- namespace, name, attributes
1097
-- name, attributes
1098
-- name
1099 1100
function
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
1120
end
1121