forked from exercism/scheme
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sxml.sls
144 lines (130 loc) · 3.77 KB
/
sxml.sls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!chezscheme
(library (sxml)
(export make-char-quotator
foldts
send-reply
pre-post-order
;;
nodeset?
element?
attr-list
content-raw
ncname
name
tag
)
(import (chezscheme))
(define make-char-quotator
(lambda (char-encoding)
(lambda (S)
(let ((n (string-length S)))
(let loop ((b 0) (chunks '()) (a 0))
(if (>= b n)
(if (zero? a)
S
(reverse (cons (substring S a b) chunks)))
(cond ((assq (string-ref S b) char-encoding)
=> (lambda (quot)
(loop (1+ b)
(cons* (cdr quot) (substring S a b) chunks)
(1+ b))))
(else (loop (1+ b) chunks a)))))))))
(define (nodeset? x)
(or (and (pair? x)
(not (symbol? (car x))))
(null? x)))
(define element?
(lambda (obj)
(and (pair? obj)
(symbol? (car obj))
(not (memq (car obj)
'(@ @@ *PI* *COMMENT* *ENTITY*))))))
(define attr-list
(lambda (obj)
(if (and (element? obj)
(not (null? (cdr obj)))
(pair? (cadr obj))
(eq? '@ (caadr obj)))
(cdadr obj)
'())))
(define name car)
(define tag car)
(define ncname
(lambda (attr)
(symbol->string (name attr))))
(define content-raw
(lambda (obj)
((if (and (not (null? (cdr obj)))
(pair? (cadr obj)) (eq? (caadr obj) '@))
(if (and (not (null? (cddr obj)))
(pair? (caddr obj)) (eq? (caaddr obj) '@@))
cdddr
cddr)
cdr)
obj)))
(define send-reply
(lambda fragments
(let loop ((fragments fragments) (result #f))
(cond ((null? fragments) result)
((not (car fragments)) (loop (cdr fragments) result))
((null? (car fragments)) (loop (cdr fragments) result))
((eq? #t (car fragments)) (loop (cdr fragments) #t))
((pair? (car fragments))
(loop (cdr fragments) (loop (car fragments) result)))
((procedure? (car fragments))
((car fragments))
(loop (cdr fragments) #t))
(else
(display (car fragments))
(loop (cdr fragments) #t))))))
(define (pre-post-order tree bindings)
(let* ((default-binding (assq '*default* bindings))
(text-binding (or (assq '*text* bindings) default-binding))
(text-handler ; Cache default and text bindings
(and text-binding
(if (procedure? (cdr text-binding))
(cdr text-binding) (cddr text-binding)))))
(let loop ((tree tree))
(cond ((null? tree) '())
((not (pair? tree))
(let ((trigger '*text*))
(if text-handler
(text-handler trigger tree)
(error 'pre-post-order
(format "Unknown binding for ~a and no default"
trigger)))))
;; tree is a nodelist
((not (symbol? (car tree)))
(map loop tree))
;; tree is an SXML node
(else
(let* ((trigger (car tree))
(binding (or (assq trigger bindings)
default-binding)))
(cond ((not binding)
(error 'pre-post-order
(format "Unknown binding for ~a and no default"
trigger)))
((not (pair? (cdr binding))) ; must be a procedure: handler
(apply (cdr binding) trigger (map loop (cdr tree))))
((eq? '*preorder* (cadr binding))
(apply (cddr binding) tree))
((eq? '*macro* (cadr binding))
(loop (apply (cddr binding) tree)))
(else ; (cadr binding) is a local binding
(apply (cddr binding) trigger
(pre-post-order (cdr tree)
(append (cadr binding)
bindings)))))))))))
(define (foldts fdown fup fhere seed tree)
(cond ((null? tree) seed)
;; An atom
((not (pair? tree))
(fhere seed tree))
(else
(let loop ((kid-seed (fdown seed tree)) (kids (cdr tree)))
(if (null? kids)
(fup seed kid-seed tree)
(loop (foldts fdown fup fhere kid-seed (car kids))
(cdr kids)))))))
)