diff --git a/main.rkt b/main.rkt index 2f9a07a..735ba6f 100644 --- a/main.rkt +++ b/main.rkt @@ -1,6 +1,6 @@ #lang racket/base (require (for-syntax racket/base)) -(require racket/match xml racket/string) +(require racket/match xml racket/string racket/list racket/bool) (module+ safe (require racket/contract)) @@ -166,12 +166,6 @@ (any/c . -> . boolean?) (ormap (λ(test) (test x)) (list txexpr-attr? txexpr-attrs? can-be-txexpr-attr-key? can-be-txexpr-attr-value?))) -(define (flatten orig-sexp) - (let loop ([sexp orig-sexp] [acc null]) - (cond [(null? sexp) acc] - [(pair? sexp) (loop (car sexp) (loop (cdr sexp) acc))] - [else (cons sexp acc)]))) - (define+provide+safe (attrs->hash . items) (() #:rest (listof can-be-txexpr-attrs?) . ->* . hash?) ;; can be liberal with input because they're all just nested key/value pairs @@ -215,6 +209,15 @@ (with-handlers ([exn:fail? (λ(e) (error (format "attr-ref: no value found for key ~v" key)))]) (hash-ref (attrs->hash (get-attrs tx)) key))) +(define+provide+safe (attr-ref* tx key) + (txexpr? can-be-txexpr-attr-key? . -> . (listof txexpr-attr-value?)) + (filter-not false? + (flatten + (let loop ([tx tx]) + (and (txexpr? tx) + (cons (and (attrs-have-key? tx key)(attr-ref tx key)) + (map loop (get-elements tx)))))))) + ;; convert list of alternating keys & values to attr (define+provide+safe (merge-attrs . items) (() #:rest (listof can-be-txexpr-attrs?) . ->* . txexpr-attrs?) diff --git a/scribblings/txexpr.scrbl b/scribblings/txexpr.scrbl index 0ba63b3..d866f22 100644 --- a/scribblings/txexpr.scrbl +++ b/scribblings/txexpr.scrbl @@ -343,6 +343,19 @@ Given a @racket[_key], look up the corresponding @racket[_value] in the attribut (attr-ref tx 'nonexistent-key) ] +@defproc[ +(attr-ref* +[tx txexpr?] +[key can-be-txexpr-attr-key?]) +(listof txexpr-attr-value?)] +Like @racket[attr-ref], but returns a recursively gathered list of all the @racket[_value]s for that key within @racket[_tx]. Asking for a nonexistent key produces @racket[null]. + +@examples[#:eval my-eval +(define tx '(div [[class "red"]] "Hello" (em ([class "blue"]) "world"))) +(attr-ref* tx 'class) +(attr-ref* tx 'nonexistent-key) +] + @defproc[ (attr-set diff --git a/tests.rkt b/tests.rkt index 192850e..2e10cb3 100644 --- a/tests.rkt +++ b/tests.rkt @@ -137,6 +137,12 @@ '(p "boing" "boing" (em "boing"))) +(check-equal? (attr-ref* '(root ((foo "bar")) "hello" "world" (meta ((foo "zam")) "bar2") + (em ((foo "zam")) "goodnight" "moon")) 'foo) '("bar" "zam" "zam")) + +(check-equal? (attr-ref* '(root ((foo "bar")) "hello" "world" (meta ((foo "zam")) "bar2") + (em ((foo "zam")) "goodnight" "moon")) 'nonexistent-key) '()) + (define split-this-tx '(root (meta "foo" "bar") "hello" "world" (meta "foo2" "bar2") (em "goodnight" "moon" (meta "foo3" "bar3"))))