On this page:
default-element-function
define-element
ref-attr
5.2.1 Working with elements
element?
attr?
element-parts
make-element
element-tag
element-attrs
element-children
set-attr
remove-attr
element-map
element-find
element-find*
element

5.2 Elements🔗

 (require punct/element) package: punct-lib

The bindings documented in this section are also provided by punct/core. The bindings in Working with elements are provided only by punct/element.

procedure

(default-element-function tag 
  default-attr-kw 
  default-attr-val ...) 
 → (->* () #:rest any/c xexpr?)
  tag : symbol?
  default-attr-kw : keyword?
  default-attr-val : string?
Returns a function which produces a tag custom element. This function takes any number of keyword arguments (which are converted to attributes) and non-keyword arguments (which become the child elements of this returned element).

You can also give keyword/value arguments to default-element-function itself; these will be set as default attributes/values in the custom element returned by the resulting function.

Examples:
> (define aside (default-element-function 'aside))
> (aside "Hello")

'(aside "Hello")

> (define kbd (default-element-function 'kbd #:alt "foo"))
> (kbd "CTRL")

'(kbd ((alt "foo")) "CTRL")

> (kbd "CTRL" #:data-code "1")

'(kbd ((alt "foo") (data-code "1")) "CTRL")

If a keyword argument supplied at the call site has the same name as one of the default attributes, the call-site value overrides the default rather than duplicating it:

Examples:
> (define span (default-element-function 'span #:class "default"))
> (span "with default" #:id "a")

'(span ((class "default") (id "a")) "with default")

> (span "overridden" #:class "custom")

'(span ((class "custom")) "overridden")

Attribute values must be strings. A keyword argument whose value is #f is left out, which makes it easy to include an attribute only some of the time, and to remove a default at the call site. Any other value raises an error.

Examples:
> (span "no class" #:class #f)

'(span "no class")

> (span "count" #:count 3)

span: attribute values must be strings or #f

  attribute: 'count

  value: 3

On Mac OS, type ALT+6 to produce § and ALT+7 to produce .

If tag ends in either § or , the resulting function will add a default block attribute of "root" or "single" respectively:

Examples:
> (define info (default-element-function 'info§))
> (info "Note!")

'(info ((block "root")) "Note!")

> (define mypar (default-element-function 'mypar¶))
> (mypar "Walnuts")

'(mypar ((block "single")) "Walnuts")

If tag has a suffix of the form .foo, the resulting function will add a default 'class attribute whose value is set to "foo". Multiple such suffixes will add additional values to the 'class attribute.

Examples:
> (define carton (default-element-function 'carton.xyz.abc))
> (carton "Cashews")

'(carton ((class "xyz abc")) "Cashews")

> (define crate (default-element-function 'crate¶.foo))
> (crate "Pecans")

'(crate ((block "single") (class "foo")) "Pecans")

Added in version 1.3 of package punct-lib.
Changed in version 1.5: Keyword arguments with a value of #f are left out; other values that are not strings raise an error.

syntax

(define-element id [default-attr-kw default-attr-val ...])

(define-element id tag [default-attr-kw default-attr-val ...])
 
  default-attr-kw : keyword?
  default-attr-val : string?
Shorthand macro for default-element-function.

If tag is supplied, it is used as the tag for the X-expressions generated by the resulting function:

> (define-element bowl container.bowl)
> (bowl "Corn nuts")

'(container ((class "bowl")) "Corn nuts")

> (define-element jar vessel¶ #:type "Glass")
> (jar "Chestnuts")

'(vessel ((type "Glass") (block "single")) "Chestnuts")

If tag is not supplied, the first argument is used both as the identifier for the function and for the tag in generated X-expressions:

> (define-element bag.xyz.abc)
> (bag "Sunflower seeds")

'(bag ((class "xyz abc")) "Sunflower seeds")

> (define-element packet¶.foo)
> (packet "Raisins")

'(packet ((block "single") (class "foo")) "Raisins")

As with default-element-function, keyword arguments at the call site override any matching defaults:

> (define-element note aside§ #:class "info")
> (note "A note")

'(aside ((class "info") (block "root")) "A note")

> (note "A warning" #:class "warning")

'(aside ((block "root") (class "warning")) "A warning")

Added in version 1.3 of package punct-lib.

procedure

(ref-attr attrs key [default]) → any/c

  attrs : (listof attr?)
  key : symbol?
  default : any/c = #f
Returns the value of the key attribute in attrs, or default if there is no such attribute. This is useful in a fallback function, which receives the attributes of an element as a separate list.

Examples:
> (ref-attr '((class "info") (id "a")) 'id)

"a"

> (ref-attr '((class "info")) 'id)

#f

> (ref-attr '((class "info")) 'id "none")

"none"

Changed in version 1.5 of package punct-lib: Added the default argument.

5.2.1 Working with elements🔗

These functions take apart, change and search the elements produced by Punct’s parse. They follow the same rules Punct uses everywhere:

  • An element is any non-empty list whose first item is a symbol (its tag).

  • If the second item is a list of attributes (each a two-item list of a symbol and a string), it is the element’s attribute list. Everything after that is a child.

  • Children are not checked: they can be strings, other elements, or any other values.

In the interests of speed, the implementations of these functions do not use contracts or check their arguments. The signatures below describe what each function expects; if you give it something else, expect error messages.
Note that the xml library also provides bindings named element, element? and make-element. If you need both libraries in one module, use only-in or prefix-in for one of them.

procedure

(element? v) → boolean?

  v : any/c
Returns #t if v is a non-empty list whose first item is a symbol.

Examples:
> (element? '(p "Hello"))

#t

> (element? '(br))

#t

> (element? "Hello")

#f

> (element? '())

#f

Added in version 1.5 of package punct-lib.

procedure

(attr? v) → boolean?

  v : any/c
Returns #t if v is a two-item list of a symbol and a string.

Examples:
> (attr? '(class "info"))

#t

> (attr? '(count 3))

#f

Added in version 1.5 of package punct-lib.

procedure

(element-parts elem) → 
symbol? (listof attr?) list?
  elem : element?
Returns the tag, attributes and children of elem. The attributes are '() if elem has none.

A list in the second position that has a value that is not a string is not an attribute list, so it is returned as the first child.

Examples:
> (element-parts '(p ((class "x")) "a" (em "b")))

'p

'((class "x"))

'("a" (em "b"))

> (element-parts '(p "a"))

'p

'()

'("a")

> (element-parts '(p ((count 3)) "a"))

'p

'()

'(((count 3)) "a")

Added in version 1.5 of package punct-lib.

procedure

(make-element tag [attrs children]) → element?

  tag : symbol?
  attrs : (listof attr?) = '()
  children : list? = '()
Builds an element. If attrs is empty, it is left out.

Examples:
> (make-element 'p '((class "x")) '("a"))

'(p ((class "x")) "a")

> (make-element 'p '() '("a"))

'(p "a")

Added in version 1.5 of package punct-lib.

procedure

(element-tag elem) → symbol?

  elem : element?

procedure

(element-attrs elem) → (listof attr?)

  elem : element?

procedure

(element-children elem) → list?

  elem : element?
Return one part of elem. See element-parts.

Added in version 1.5 of package punct-lib.

procedure

(set-attr attrs key val) → (listof attr?)

  attrs : (listof attr?)
  key : symbol?
  val : string?
Returns attrs with the key attribute set to val. An existing attribute keeps its position; a new one is added at the end.

Examples:
> (set-attr '((href "/x") (title "X")) 'href "/y")

'((href "/y") (title "X"))

> (set-attr '((href "/x")) 'rel "external")

'((href "/x") (rel "external"))

Added in version 1.5 of package punct-lib.

procedure

(remove-attr attrs key) → (listof attr?)

  attrs : (listof attr?)
  key : symbol?
Returns attrs without the key attribute.

Example:
> (remove-attr '((id "a") (class "x")) 'id)

'((class "x"))

Added in version 1.5 of package punct-lib.

procedure

(element-map proc v) → any/c

  proc : (-> any/c any/c)
  v : any/c
Calls proc on v and every node inside it, children first, and builds a new tree from the results. Because children are done first, proc receives each element with its children already replaced. proc receives strings and other non-element values too, but never attribute lists.

Examples:
> (element-map (λ (x) (if (string? x) (string-upcase x) x))
               '(p ((class "x")) "a" (em "b")))

'(p ((class "x")) "A" (em "B"))

> (require racket/match)
> (element-map (match-lambda
                 [(element 'a attrs kids) (make-element 'a (set-attr attrs 'rel "external") kids)]
                 [x x])
               '(p "See " (a ((href "https://example.com")) "this")))

'(p "See " (a ((href "https://example.com") (rel "external")) "this"))

Added in version 1.5 of package punct-lib.

procedure

(element-find pred v) → (or/c element? #f)

  pred : (-> element? any/c)
  v : any/c

procedure

(element-find* pred v) → (listof element?)

  pred : (-> element? any/c)
  v : any/c
Search v and the elements inside it, in document order: a parent comes before its children. Only elements are passed to pred. element-find returns the first element for which pred returns a true value, or #f; element-find* returns all of them, or '().

Examples:
> (define (link? e) (eq? (element-tag e) 'link))
> (define body '(paragraph (link ((dest "/a")) "A") " and " (bold (link ((dest "/b")) "B"))))
> (element-find link? body)

'(link ((dest "/a")) "A")

> (element-find* link? body)

'((link ((dest "/a")) "A") (link ((dest "/b")) "B"))

> (element-find* (λ (e) (eq? (element-tag e) 'table)) body)

'()

Added in version 1.5 of package punct-lib.

match expander

(element tag-pat attrs-pat children-pat)

Matches an element, and matches its tag, attributes and list of children against the three patterns. attrs-pat is matched against '() if the element has no attributes.

Examples:
> (match '(a ((href "/x")) "X")
    [(element 'a (list-no-order (list 'href url) _ ...) kids) (list url kids)])

'("/x" ("X"))

> (match '(p "Hello")
    [(element tag '() kids) (list tag kids)])

'(p ("Hello"))

Added in version 1.5 of package punct-lib.