#cs(module id mzscheme
(require "common.ss")
(require "myenv.ss")
(require "access-remote.ss")
(require "sxpathlib.ss")
(define (id:process-s port)
(let ((symb (peek-char port)))
(cond((eof-object? symb) symb)
((char=? symb #\space) (read-char port)
(id:process-s port))
((char=? symb #\return) (read-char port)
(id:process-s port))
((char=? symb #\newline)(read-char port)
(id:process-s port))
((char=? symb #\tab)(read-char port)
(id:process-s port))
(else symb))))
(define (id:ignore-until templ-sym port)
(let loop ((symb (peek-char port)))
(cond((eof-object? symb) symb)
((equal? symb templ-sym) (read-char port)
symb)
(else (read-char port)
(loop (peek-char port))))))
(define (id:read-n num port)
(id:process-s port)
(let loop ((num num) (res '()))
(if(= num 0)
(list->string (reverse res))
(let((symb (peek-char port)))
(cond((eof-object? symb) symb)
(else (read-char port)
(loop (- num 1) (cons symb res))))))))
(define (id:read-name port)
(id:process-s port)
(let loop ((res ""))
(let ((symb (peek-char port)))
(cond((eof-object? symb) res)
((member symb '(#\space #\tab #\return #\newline
#\< #\> #\( #\) #\[ #\] #\|))
res)
(else (loop (string-append res (string (read-char port)))))))))
(define (id:process-literal port)
(id:process-s port)
(let((quot (peek-char port)))
(if(eof-object? quot) ""
(let((quot (if (char=? (read-char port) #\") #\" #\')))
(let loop ((res '()))
(let((symb (peek-char port)))
(cond
((eof-object? symb) (list->string (reverse res)))
((char=? symb quot) (read-char port)
(list->string (reverse res)))
(else
(read-char port)
(loop (cons symb res))))))))))
(define (id:to-small str)
(let loop ((arg (string->list str)) (res '()))
(cond((null? arg) (list->string (reverse res)))
((char-upper-case? (car arg))
(loop (cdr arg) (cons (char-downcase (car arg)) res)))
(else (loop (cdr arg) (cons (car arg) res))))))
(define (id:unite-id-attrs id-attrs)
(let loop ((id-attrs id-attrs)
(new '()))
(if
(null? id-attrs)
new
(let rpt ((elem-name (caar id-attrs))
(atts (cdar id-attrs))
(rest (cdr id-attrs))
(id-attrs '()))
(cond
((null? rest)
(loop id-attrs (cons (cons elem-name atts) new)))
((equal? (caar rest) elem-name)
(rpt elem-name
(append atts (cdar rest))
(cdr rest)
id-attrs))
(else
(rpt elem-name atts (cdr rest) (cons (car rest) id-attrs))))))))
(define (id:ignore-PI port)
(id:ignore-until #\? port)
(let ((symb (peek-char port)))
(cond((eof-object? symb) symb)
((equal? symb #\>) (read-char port)
symb)
(else (id:ignore-PI port)))))
(define (id:ignore-comment port)
(read-char port) (read-char port) (id:ignore-until #\- port)
(let((sym1 (peek-char port)))
(cond((eof-object? sym1) sym1)
((char=? sym1 #\-) (read-char port)
(let((sym2 (read-char port))) sym2))
(else (id:ignore-comment port)))))
(define (id:AttType-ID? port)
(let((type (id:to-small (id:read-name port))))
(cond((string=? type "id") #t)
((string=? type "notation")
(id:process-s port)
(read-char port) (id:ignore-until #\) port)
#f)
((and (string=? type "") (char=? (peek-char port) #\()) (id:ignore-until #\) port)
#f)
(else #f))))
(define (id:process-DefaultDecl port)
(let((type (id:to-small (id:read-name port))))
(cond((string=? type "#fixed")
(id:read-name port) #t)
(else #t))))
(define (id:process-AttDef port)
(let((att-name (string->symbol (id:read-name port))))
(let((bool (id:AttType-ID? port)))
(id:process-DefaultDecl port)
(if bool (list att-name) '()))))
(define (id:process-AttlistDecl port)
(let((element-name (string->symbol (id:read-name port))))
(let loop ((atts '()))
(id:process-s port)
(cond((char=? (peek-char port) #\>) (read-char port)
(if(null? atts)
'()
(list (cons element-name atts))))
(else
(loop (append (id:process-AttDef port) atts)))))))
(define (id:process-markupdecl* port)
(let loop ((id-attrs '()))
(let((beg (id:read-n 2 port)))
(cond((eof-object? beg) id-attrs) ((string=? beg "]>") id-attrs) ((string=? beg "<?") (id:ignore-PI port)
(loop id-attrs))
((and (string=? beg "<!") (char=? (peek-char port) #\-)) (id:ignore-comment port)
(loop id-attrs))
((string=? beg "<!") (let ((name (id:to-small (id:read-name port))))
(cond((string=? name "attlist")
(loop (append (id:process-AttlistDecl port) id-attrs)))
(else
(id:ignore-until #\> port)
(loop id-attrs)))))
(else (cerr "Error in markupdecl production: unexpected " beg nl)
(id:ignore-until #\> port)
id-attrs)))))
(define (id:process-ExternalID port)
(let((system-literal
(let((name (id:to-small (id:read-name port))))
(cond
((string=? name "system")
(id:process-literal port))
((string=? name "public")
(id:process-literal port)
(id:process-literal port))
(else #f)))))
(if(not system-literal)
'() (let((external-port (open-input-resource system-literal)))
(if(not external-port)
'() (let((id-attrs (id:process-markupdecl* external-port)))
(close-input-port external-port)
id-attrs))))))
(define (id:process-doctypedecl port)
(let((name (id:read-name port))) (id:process-s port)
(let((symb (peek-char port)))
(cond
((eof-object? symb) '()) ((char=? symb #\[)
(read-char port)
(id:process-markupdecl* port))
(else
(let((id-attrs (id:process-ExternalID port)))
(id:process-s port)
(let((symb (peek-char port)))
(cond
((eof-object? symb) id-attrs) ((char=? symb #\[)
(read-char port)
(append id-attrs (id:process-markupdecl* port)))
(else id-attrs)))))))))
(define (id:process-prolog port)
(let((beg (id:read-n 2 port)))
(cond((eof-object? beg) '()) ((string=? beg "<?") (id:ignore-PI port)
(id:process-prolog port))
((and (string=? beg "<!") (char=? (peek-char port) #\-)) (id:ignore-comment port)
(id:process-prolog port))
((string=? beg "<!") (let ((name (id:to-small (id:read-name port))))
(cond((string=? name "doctype")
(id:process-doctypedecl port))
(else
(cerr "doctypedecl production expected" nl)
'()))))
(else '()))))
(define (id:read-external-dtd uri-string)
(let((port (open-input-resource uri-string)))
(if(not port)
'() (let((id-attrs (id:unite-id-attrs (id:process-markupdecl* port))))
(close-input-port port)
id-attrs))))
(define (id:read-document-declaration uri-string)
(let((port (open-input-resource uri-string)))
(if(not port)
'() (let((id-attrs (id:unite-id-attrs (id:process-prolog port))))
(close-input-port port)
id-attrs))))
(define (SXML->SXML+id document id-attrs)
(let((aux-subtrees
(let((aux ((select-kids (ntype?? '@@)) document)))
(if(null? aux)
'()
(let rpt ((res '())
(to-see (cdar aux)))
(cond
((null? to-see) (reverse res))
((equal? (caar to-see) 'id-index) (rpt res (cdr to-see)))
(else (rpt (cons (car to-see) res)
(cdr to-see)))))))))
(let loop ((nodeset (list document))
(id-index '()))
(if(null? nodeset)
(let((kids ((select-kids
(lambda (node)
(not (and (pair? node) (equal? (car node) '@@)))))
document)))
(cons* '*TOP*
(cons* '@@
(cons 'id-index id-index)
aux-subtrees)
kids))
(let((cur-node (car nodeset)))
(cond
((not (pair? cur-node)) (loop (cdr nodeset) id-index))
((assoc (car cur-node) id-attrs)
=>
(lambda (lst)
(let((id-values
((select-kids (lambda (x) #t))
((sxml:filter (lambda (x) (member (car x) (cdr lst))))
((select-kids (lambda (x) #t))
((select-kids (ntype?? '@)) cur-node))))))
(loop
(append
((select-kids (ntype?? '*)) (car nodeset))
(cdr nodeset))
(append
id-index
(map
(lambda (x) (cons x cur-node))
id-values))))))
(else
(loop
(append ((select-kids (ntype?? '*)) (car nodeset)) (cdr nodeset))
id-index))))))))
(define (id:make-seed id-attrs id-index)
(list id-attrs id-index))
(define (id:seed-attrs id:seed)
(car id:seed))
(define (id:seed-index id:seed)
(cadr id:seed))
(define (id:new-level-seed-handler id:seed)
id:seed)
(define (id:finish-element-handler elem-gi attributes id:seed element)
(cond
((assoc elem-gi (id:seed-attrs id:seed))
=>
(lambda (lst)
(let loop ((atts attributes)
(id-index (id:seed-index id:seed)))
(if
(null? atts)
(id:make-seed (id:seed-attrs id:seed) id-index)
(let((att (car atts)))
(cond
((pair? (car att)) (loop (cdr atts) id-index))
((member (car att) (cdr lst))
(loop (cdr atts)
(cons (cons (cdr att) element) id-index)))
(else
(loop (cdr atts) id-index))))))))
(else
id:seed)))
(define (id:doctype-handler port systemid internal-subset?)
(let((id-attrs
(if
(not systemid)
'() (let((external-port (open-input-resource systemid)))
(if
(not external-port)
'() (let((id-attrs (id:process-markupdecl* external-port)))
(close-input-port external-port)
id-attrs))))))
(let((id-attrs
(if
internal-subset?
(id:unite-id-attrs
(append id-attrs (id:process-markupdecl* port)))
(id:unite-id-attrs id-attrs))))
(id:make-seed id-attrs '()))))
(define (id:ending-action id:seed)
(let((id-index (id:seed-index id:seed)))
(cons 'id-index id-index)))
(provide (all-defined)))