ovidiu 02/01/18 17:02:23 Modified: src/scratchpad/schecoon/scheme sitemap.scm Log: Define sitemap-parse! to parse the XML representation of the sitemap into Scheme. Revision Changes Path 1.4 +259 -226 xml-cocoon2/src/scratchpad/schecoon/scheme/sitemap.scm Index: sitemap.scm =================================================================== RCS file: /home/cvs/xml-cocoon2/src/scratchpad/schecoon/scheme/sitemap.scm,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- sitemap.scm 17 Jan 2002 18:06:16 -0000 1.3 +++ sitemap.scm 19 Jan 2002 01:02:22 -0000 1.4 @@ -6,7 +6,7 @@ (load-module "sisc.modules.Regexp") (load-module "sisc.modules.J2S") -(load-module "org.apache.cocoon.scheme.sitemap.SchemeSitemap") +(load-module "org.apache.cocoon.scheme.sitemap.SchemeSitemapFunctions") ;; A Cocoon XML sitemap description is processed by the Scheme code in ;; this file. The processing happens in several steps: @@ -46,15 +46,15 @@ ;; (pipelines (@ (*line* 1)) ;; (pipeline (@ (*line* 2)) ;; (match (@ (pattern "documentation/(.*).html") (*line* 3)) -;; (generate (@ (src "docs/{1}.xml") (type "file") (*line* 4)) -;; (param (@ (name "test") (value "123") (*line* 5))) -;; (transform (@ (src "stylesheets/document2html.xsl") (@ (*line* 6))) -;; (param (@ (name "test2") (value "456") (@ (*line* 7)))) -;; (serialize (@ (*line* 8))) -;; ) +;; (generate (@ (src "docs/{1}.xml") (type "file") (*line* 4)) +;; (param (@ (name "test") (value "123") (*line* 5))) +;; (transform (@ (src "stylesheets/document2html.xsl") (@ (*line* 6))) +;; (param (@ (name "test2") (value "456") (@ (*line* 7)))) +;; (serialize (@ (*line* 8))) +;; ) ;; ;; (match (@ (pattern "sites/images/(.*).gif") (*line* 10)) -;; (read (@ (src "{1}") (mime-type "image/gif") (@ (*line* 11))))) +;; (read (@ (src "{1}") (mime-type "image/gif") (@ (*line* 11))))) ;; ))) ;; ;; The line numbers where an element starts are added by the XML @@ -65,46 +65,46 @@ ;; ;;(define the-sitemap ;; (let ((rx1 (regexp "documentation/(.*).html")) -;; (rx2 (regexp "sites/images/(.*).gif"))) +;; (rx2 (regexp "sites/images/(.*).gif"))) ;; (define (p1 url sitemap env) ;; (let ((result (regexp-match rx1 url))) -;; (if result -;; (apply -;; (lambda (arg1 . rest) -;; (sitemap:process -;; sitemap env '() -;; (sitemap:serialize -;; sitemap env '() -;; (sitemap:transform -;; sitemap env -;; (list (cons 'params (list (cons "test" "123") -;; (cons "test2" "456"))) -;; (cons 'src "stylesheets/document2html.xsl")) -;; (sitemap:generate -;; sitemap env -;; (list (cons 'params (list (cons "test" "123") -;; (cons "test2" "456"))) -;; (cons 'src (string-append "docs/" arg1 ".xml")) -;; (cons 'type "file"))))))) -;; (cdr result)) -;; #f))) +;; (if result +;; (apply +;; (lambda (arg1 . rest) +;; (sitemap:process +;; sitemap env '() +;; (sitemap:serialize +;; sitemap env '() +;; (sitemap:transform +;; sitemap env +;; (list (cons 'params (list (cons "test" "123") +;; (cons "test2" "456"))) +;; (cons 'src "stylesheets/document2html.xsl")) +;; (sitemap:generate +;; sitemap env +;; (list (cons 'params (list (cons "test" "123") +;; (cons "test2" "456"))) +;; (cons 'src (string-append "docs/" arg1 ".xml")) +;; (cons 'type "file"))))))) +;; (cdr result)) +;; #f))) ;; ;; (define (p2 url sitemap env) ;; (let ((result (regexp-match rx2 url))) -;; (if result -;; (apply (lambda (arg1 . rest) -;; (sitemap:process -;; sitemap env '() -;; (sitemap:read -;; sitemap env -;; '(("src" . (string-append "" arg1 "")) -;; ("mime-type" . "image/gif"))))) -;; (cdr result)) -;; #f))) +;; (if result +;; (apply (lambda (arg1 . rest) +;; (sitemap:process +;; sitemap env '() +;; (sitemap:read +;; sitemap env +;; '(("src" . (string-append "" arg1 "")) +;; ("mime-type" . "image/gif"))))) +;; (cdr result)) +;; #f))) ;; ;; (lambda (url sitemap env) ;; (or (p1 url sitemap env) -;; (p2 url sitemap env))))) +;; (p2 url sitemap env))))) ;; ;; ;; Notice that all the {1}, {2}, ...{n} get expanded in the body of @@ -130,20 +130,20 @@ ;; (define (process-sitemap sitemap) (let ((exit #f) - (arg-regexp (regexp "/({[0-9]+})/")) - (number-arg-regexp (regexp "[{}]")) - (match-pattern-regexp (regexp "/(\\([^)]+\\))/")) - (pattern-regexps-no 0) - (pcount 0)) + (arg-regexp (regexp "/({[0-9]+})/")) + (number-arg-regexp (regexp "[{}]")) + (match-pattern-regexp (regexp "/(\\([^)]+\\))/")) + (pattern-regexps-no 0) + (pcount 0)) ;; Print out an error message, showing the line in the XML document ;; where the error occured, if such information is present in the ;; SXML tree. (define (xml-error node message) (let ((line (sxml:attr node '*line*))) - (if line - (begin (display "In line ") (display line) (display ": "))) - (display message) (newline) (exit 'error))) + (if line + (begin (display "In line ") (display line) (display ": "))) + (display message) (newline) (exit 'error))) ;; Returns the remaining pipeline after the first element has been ;; removed. @@ -159,82 +159,82 @@ ;; If no such occurrence is found, the value is simply returned. (define (expand-value node value) (let* ((exp (regexp-split arg-regexp value)) - (length (vector-length exp))) - (if (eq? length 1) - value - `(string-append - ,@(vector->list - (let loop ((index 1)) - (if (>= index length) - exp - (let* ((arg (vector-ref exp index)) - (n (vector-ref (regexp-split/delimiter - number-arg-regexp arg) 1))) - ;; Check to see if `n' is greater than the - ;; maximum number of paranthesised - ;; expressions in the original pattern. - (if (> (string->number n) pattern-regexps-no) - (xml-error node (format "Reference to inexistent regexp pattern ~a, maximum allowed is ~s" n pattern-regexps-no))) - (if (< (string->number n) 1) - (xml-error node (format "Regexp pattern argument should be greater than 1, got ~a" n))) - (vector-set! exp index - (string->symbol (string-append "arg" n))) - (loop (+ index 2))))))) - ))) + (length (vector-length exp))) + (if (eq? length 1) + value + `(string-append + ,@(vector->list + (let loop ((index 1)) + (if (>= index length) + exp + (let* ((arg (vector-ref exp index)) + (n (vector-ref (regexp-split/delimiter + number-arg-regexp arg) 1))) + ;; Check to see if `n' is greater than the + ;; maximum number of paranthesised + ;; expressions in the original pattern. + (if (> (string->number n) pattern-regexps-no) + (xml-error node (format "Reference to inexistent regexp pattern ~a, maximum allowed is ~s" n pattern-regexps-no))) + (if (< (string->number n) 1) + (xml-error node (format "Regexp pattern argument should be greater than 1, got ~a" n))) + (vector-set! exp index + (string->symbol (string-append "arg" n))) + (loop (+ index 2))))))) + ))) ;; Collect embedded <param> elements into a list of name/value ;; pairs and return it. (define (get-params elements) (if (eq? elements '()) - '() - (let* ((nodelist ((node-pos 1) elements)) - (node (if (null? nodelist) '() (car nodelist))) - (name (sxml:attr node 'name)) - (value (sxml:attr node 'value))) - (if (null? name) - (xml-error node "Attribute 'name' is required in <param>")) - (if (null? value) - (xml-error node "Attribute 'value' is required in <param>")) - (cons `(cons ,name ,(expand-value node value)) - (get-params (rest-of-nodes elements))) - ))) + '() + (let* ((nodelist ((node-pos 1) elements)) + (node (if (null? nodelist) '() (car nodelist))) + (name (sxml:attr node 'name)) + (value (sxml:attr node 'value))) + (if (null? name) + (xml-error node "Attribute 'name' is required in <param>")) + (if (null? value) + (xml-error node "Attribute 'value' is required in <param>")) + (cons `(cons ,name ,(expand-value node value)) + (get-params (rest-of-nodes elements))) + ))) ;; Obtain the list of required and optional arguments, as well as ;; the parameters, if they are needed. (define (get-attributes node required optional allows-params) (let* ((elem-name (sxml:element-name node)) - (args '()) - (params '()) - (required-attrs - (map - (lambda (attr-name) - (let ((attr (sxml:attr node attr-name))) - (if (not attr) - (xml-error node - (format "'~s' attribute required in <~s>" - attr-name elem-name)) - `(cons ',attr-name ,(expand-value node attr))))) - required)) - (optional-attrs '())) - (for-each - (lambda (attr-name) - (let ((attr (sxml:attr node attr-name))) - (if attr - (set! optional-attrs - (cons `(cons ',attr-name ,(expand-value node attr)) - optional-attrs))))) - optional) - - (if (not (null? required-attrs)) - (set! args (append args required-attrs))) - (if (not (null? optional-attrs)) - (set! args (append args optional-attrs))) - (if allows-params - (begin - (set! params (get-params (sxml:content node))) - (if (not (null? params)) - (set! args (cons `(cons 'params (list ,@params)) args))))) - (if (null? args) `('()) `((list ,@args))))) + (args '()) + (params '()) + (required-attrs + (map + (lambda (attr-name) + (let ((attr (sxml:attr node attr-name))) + (if (not attr) + (xml-error node + (format "'~s' attribute required in <~s>" + attr-name elem-name)) + `(cons ',attr-name ,(expand-value node attr))))) + required)) + (optional-attrs '())) + (for-each + (lambda (attr-name) + (let ((attr (sxml:attr node attr-name))) + (if attr + (set! optional-attrs + (cons `(cons ',attr-name ,(expand-value node attr)) + optional-attrs))))) + optional) + + (if (not (null? required-attrs)) + (set! args (append args required-attrs))) + (if (not (null? optional-attrs)) + (set! args (append args optional-attrs))) + (if allows-params + (begin + (set! params (get-params (sxml:content node))) + (if (not (null? params)) + (set! args (cons `(cons 'params (list ,@params)) args))))) + (if (null? args) `('()) `((list ,@args))))) ;; The following match- functions should probably be transformed ;; into a macro, and described at a much higher level than now. A @@ -243,101 +243,101 @@ ;; Translate a <generate> element. (define (match-generate pipeline) (let* ((nodelist ((node-pos 1) pipeline)) - (node (if (null? nodelist) '() (car nodelist)))) - (if (not (eq? (sxml:element-name node) 'generate)) - #f - (begin - (let ((args (get-attributes node '(src) '(type) #t))) - (match-transform - (rest-of-nodes pipeline) - `(sitemap:generate sitemap env ,@args)) - ))))) + (node (if (null? nodelist) '() (car nodelist)))) + (if (not (eq? (sxml:element-name node) 'generate)) + #f + (begin + (let ((args (get-attributes node '(src) '(type) #t))) + (match-transform + (rest-of-nodes pipeline) + `(sitemap:generate sitemap env ,@args)) + ))))) ;; Translate zero or more <transform> elements (define (match-transform pipeline compfunc) (let* ((nodelist ((node-pos 1) pipeline)) - (node (if (null? nodelist) '() (car nodelist)))) - (cond - ((eq? (sxml:element-name node) 'transform) - (let ((args (get-attributes node '(src) '(type) #t))) - (match-transform - (rest-of-nodes pipeline) - `(sitemap:transform sitemap env ,@args ,compfunc)) - )) - (else (match-serialize pipeline compfunc)) - ))) + (node (if (null? nodelist) '() (car nodelist)))) + (cond + ((eq? (sxml:element-name node) 'transform) + (let ((args (get-attributes node '(src) '(type) #t))) + (match-transform + (rest-of-nodes pipeline) + `(sitemap:transform sitemap env ,@args ,compfunc)) + )) + (else (match-serialize pipeline compfunc)) + ))) ;; Transform zero or one <serializer> elements (define (match-serialize pipeline compfunc) (let* ((nodelist ((node-pos 1) pipeline)) - (node (if (null? nodelist) '() (car nodelist)))) - (cond - ;; A serializer has been explicitly defined - ((eq? (sxml:element-name node) 'serialize) - (let ((args (get-attributes node '() '(type mime-type) #t))) - (match-pipeline-end - (rest-of-nodes pipeline) - `(sitemap:serialize sitemap env ,@args ,compfunc)))) - - ;; End of the pipeline with no serializer specified - ((eq? node '()) - `(sitemap:serialize sitemap env ,compfunc)) - - ;; Anything else is an error - (else - (xml-error node "Only <transformer> or <serialize> allowed here")) - ))) + (node (if (null? nodelist) '() (car nodelist)))) + (cond + ;; A serializer has been explicitly defined + ((eq? (sxml:element-name node) 'serialize) + (let ((args (get-attributes node '() '(type mime-type) #t))) + (match-pipeline-end + (rest-of-nodes pipeline) + `(sitemap:serialize sitemap env ,@args ,compfunc)))) + + ;; End of the pipeline with no serializer specified + ((eq? node '()) + `(sitemap:serialize sitemap env ,compfunc)) + + ;; Anything else is an error + (else + (xml-error node "Only <transformer> or <serialize> allowed here")) + ))) ;; Translate a <read> element (define (match-reader pipeline) (let* ((nodelist ((node-pos 1) pipeline)) - (node (if (null? nodelist) '() (car nodelist)))) - (cond - ((eq? (sxml:element-name node) 'read) - (let ((args (get-attributes node '(src) '(type mime-type) #t))) - (match-pipeline-end - (rest-of-nodes pipeline) - `(sitemap:read sitemap env ,@args)) - )) - (else #f) - ))) + (node (if (null? nodelist) '() (car nodelist)))) + (cond + ((eq? (sxml:element-name node) 'read) + (let ((args (get-attributes node '(src) '(type mime-type) #t))) + (match-pipeline-end + (rest-of-nodes pipeline) + `(sitemap:read sitemap env ,@args)) + )) + (else #f) + ))) ;; Make sure nothing follows the pipeline definition (define (match-pipeline-end pipeline compfunc) (let* ((nodelist ((node-pos 1) pipeline)) - (node (if (null? nodelist) '() (car nodelist)))) - (if (null? node) - compfunc - (xml-error node "No element allowed in this context")))) + (node (if (null? nodelist) '() (car nodelist)))) + (if (null? node) + compfunc + (xml-error node "No element allowed in this context")))) ;; The entry point in matching a pipeline. Transforms a pipeline ;; definition into a Scheme function whose body executes the ;; described pipeline. (define (match-pipeline pipeline) (let ((procname (string->symbol (format "p~a" pcount))) - (rxname (string->symbol (format "rx~a" pcount)))) - `(define (,procname url sitemap env) - (let ((result (regexp-match ,rxname url))) - (if result - (apply - (lambda ,(let loop ((index 1)) - (if (> index pattern-regexps-no) - 'rest - (cons - (string->symbol - (format "arg~a" (number->string index))) - (loop (+ index 1))))) - (sitemap:process - sitemap env '() - ,(or - (match-generate pipeline) - (match-reader pipeline) - (let* ((nodelist ((node-pos 1) pipeline)) - (node (if (null? nodelist) '() (car nodelist)))) - (xml-error node "Invalid pipeline definition"))))) - (cdr result)) - #f))) - )) + (rxname (string->symbol (format "rx~a" pcount)))) + `(define (,procname url sitemap env) + (let ((result (regexp-match ,rxname url))) + (if result + (apply + (lambda ,(let loop ((index 1)) + (if (> index pattern-regexps-no) + 'rest + (cons + (string->symbol + (format "arg~a" (number->string index))) + (loop (+ index 1))))) + (sitemap:process + sitemap env '() + ,(or + (match-generate pipeline) + (match-reader pipeline) + (let* ((nodelist ((node-pos 1) pipeline)) + (node (if (null? nodelist) '() (car nodelist)))) + (xml-error node "Invalid pipeline definition"))))) + (cdr result)) + #f))) + )) ;; This is the main processing function for a 'match' node in the ;; SXML representation of the sitemap. This function returns an @@ -351,20 +351,20 @@ ;; Check for the presence of the 'pattern' attribute and signal ;; an error if not present (let ((pattern (sxml:attr node 'pattern))) - (if (not pattern) - (xml-error - node "required 'pattern' attribute for <match> is not present")) - ;; Increment the pipelines count - (set! pcount (+ pcount 1)) - ;; Translate the pipeline definitions into equivalent Scheme - ;; functions - (let ((pipeline (reverse (sxml:child-elements node))) - (exp-pattern (regexp-split match-pattern-regexp pattern)) - (rxname (string->symbol (format "rx~a" pcount)))) - (set! pattern-regexps-no (/ (- (vector-length exp-pattern) 1) 2)) - (list (cons `(,rxname (regexp ,pattern)) - (match-pipeline pipeline))) - ))) + (if (not pattern) + (xml-error + node "required 'pattern' attribute for <match> is not present")) + ;; Increment the pipelines count + (set! pcount (+ pcount 1)) + ;; Translate the pipeline definitions into equivalent Scheme + ;; functions + (let ((pipeline (reverse (sxml:child-elements node))) + (exp-pattern (regexp-split match-pattern-regexp pattern)) + (rxname (string->symbol (format "rx~a" pcount)))) + (set! pattern-regexps-no (/ (- (vector-length exp-pattern) 1) 2)) + (list (cons `(,rxname (regexp ,pattern)) + (match-pipeline pipeline))) + ))) ;; Process the SXML representation of the sitemap. This is done by ;; invoking the apply-templates function on the SXML representation @@ -380,29 +380,62 @@ ;; . matcher-function). We iterate on it to construct the top ;; level function that represents the sitemap. (let* ((matchers - (apply-templates - sitemap - `((match . ,(lambda (node) (process-match node)))))) - (sitemap-code - `(let ,(let loop ((ms matchers)) - (if (null? ms) - '() - (cons (caar ms) - (loop (cdr ms))))) - ,@(let loop ((ms matchers)) - (if (null? ms) - '() - (cons (cdar ms) - (loop (cdr ms))))) - (lambda (url sitemap env) - (or ,@(let loop ((index 1)) - (if (> index pcount) - '() - (cons - (list (string->symbol (format "p~a" index)) - 'url 'sitemap 'env) - (loop (+ index 1)))))))))) -; (newline) (write sitemap-code) (newline) - (eval sitemap-code (interaction-environment)) - ))) + (apply-templates + sitemap + `((match . ,(lambda (node) (process-match node)))))) + (sitemap-code + `(let ,(let loop ((ms matchers)) + (if (null? ms) + '() + (cons (caar ms) + (loop (cdr ms))))) + ,@(let loop ((ms matchers)) + (if (null? ms) + '() + (cons (cdar ms) + (loop (cdr ms))))) + (lambda (url sitemap env) + (or ,@(let loop ((index 1)) + (if (> index pcount) + '() + (cons + (list (string->symbol (format "p~a" index)) + 'url 'sitemap 'env) + (loop (+ index 1)))))))))) +; (newline) (write sitemap-code) (newline) + (eval sitemap-code (interaction-environment)) + ))) )) + +;; `the-sitemap' will contain the compiled version of the sitemap. +(define the-sitemap #f) + +;; Invoked from the Java side to parse the XML representation of the +;; sitemap and update the `sxml-sitemap' variable. The processing of +;; the XML sitemap representation happens in two steps. +;; +;; In the first step the, using the `sitemap:parse' function, the XML +;; representation is translated into SXML. This translation happens in +;; Java, using the XMLtoSXML ContentHandler, which is invoked through +;; `sitemap:parse', a native function defined in +;; SchemeSitemapFunctions. +;; +;; In the second step, the SXML representation of the sitemap is +;; converted to a Scheme function, using the `process-sitemap' +;; function defined above. The result of this processing, the +;; "executable" sitemap function is set as value for `the-sitemap' +;; variable. +;; +;; When an HTTP request is to be processed by Cocoon, the +;; SchemeSitemap#process method will invoke the main function, usually +;; defined as `main'. This will simply call the function stored in +;; `the-sitemap'. +(define (sitemap-parse! manager source) + (let ((sxml (sitemap:parse manager source)) + (xsxml (process-sitemap sxml))) + (set! the-sitemap xsxml))) + +;; This is the main entry point in the Scheme Cocoon sitemap. This +;; function is invoked from the SchemeSitemap#process method. +(define (main url sitemap environment) + (the-sitemap url sitemap environment))
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]