#lang scribble/doc
@(require scribble/manual
"util.rkt"
(for-label (this-package-in main)))
@title{SXML}
@deftech{SXML} is a representation of XML elements using
s-expressions. The following grammar describes the structure of SXML:
@(define ATSIGN (racketidfont "@"))
@racketgrammar*[
#:literals (*TOP* *PI* *COMMENT* *ENTITY* URI *NAMESPACES* |@|)
[top (*TOP* maybe-annotations
PI ...
comment ...
element)]
[element (name maybe-annot-attributes child ...)]
[annot-attributes (|@| attribute ... maybe-annotations)]
[attribute (name maybe-value maybe-annotations)]
[child element
character-data-string
PI
comment
entity]
[PI (*PI* pi-target
maybe-annotations
processing-instruction-content-string)]
[comment (*COMMENT* comment-string)]
[entity (*ENTITY* public-id-string system-id-string)]
[name local-name
exp-name]
[local-name @#,elem{symbol conforming to XML Namespace recommendation}]
[exp-name @#,elem{symbol of the form @racket[_namespace-id]@litchar{:}@racket[_local-name]}]
[namespace-id URI-symbol
user-ns-shortcut-symbol]
[namespaces (*NAMESPACES* namespace-assoc ...)]
[namespace-assoc (namespace-id uri-string maybe-original-prefix)]
[annotations (|@| maybe-namespaces annotation ...)]
[annotation @#,elem{not yet specified}]
]
Some tools, such as SXPath, use the following coarse approximation of
SXML structure for simplicity:
@racketgrammar*[
#:literals (*TOP* *PI* *COMMENT* *ENTITY* URI *NAMESPACES* |@|)
[node (name . node-list)
string]
[node-list (node ...)]
[name local-name exp-name |@| *TOP* *PI* *COMMENT* *ENTITY* *NAMESPACES*]
]
Refer to @hyperlink["http://okmij.org/ftp/Scheme/SXML.html"]{the
original SXML specification} for a more detailed explanation of the
representation, including examples.
In short, an XML element is represented as a list consisting of its
tag name as a symbol followed by its children nodes. If the XML
element has attributes, they come immediately after the tag symbol, in
a list tagged by an @racket[|@|] symbol.
For example, the XML element
@tt{defjkl}
is represented by the SXML datum
@racket['(abc "def" (ghi) "jkl")]
and the XML element
@tt{Barry White}
is represented by the SXML datum
@racket['(customer (|@| (specialness "gazonga")) "Barry White")]
That's the easy part. Things get more tricky when you start talking
about documents and namespaces.
@;{ ============================================================ }
@section{SXML Functions}
@defproc[(sxml:element? [v any/c]) boolean?]{
Returns @racket[#t] if @racket[v] is a list starting with a symbol
that is not a special symbol, @racket[#f] otherwise.
@examples[#:eval the-eval
(sxml:element? '(p "blah"))
(sxml:element? '(*COMMENT* "ignore me"))
(sxml:element? '(|@| (href "link.html")))
]
}
@defproc[(ntype-names?? [tags (listof symbol?)])
(-> any/c boolean?)]{
Given a list of allowable tag names, returns a predicate that
recognizes @racket[_element]s with those tags.
@examples[#:eval the-eval
((ntype-names?? '(a p)) '(p "blah"))
((ntype-names?? '(a p)) '(br))
]
}
@defproc[(ntype?? [crit symbol?])
(-> any/c boolean?)]{
If @racket[_crit] is a special symbol, a predicate is returned that
accepts the following classes of @racket[_node]:
@itemlist[
@item{@racket['|@|]: an @racket[_annot-attributes] node}
@item{@racket['*]: any @racket[_element] (@racket[sxml:element?])}
@item{@racket['*any*]: any @racket[_node]}
@item{@racket['*text*]: any string}
@item{@racket['*data*]: anything except a pair (@racket[_element])}
@item{@racket['*COMMENT*]: a @racket[_comment] node}
@item{@racket['*PI*]: a @racket[_PI] (processing instruction) node}
@item{@racket['*ENTITY*]: an @racket[_entity] node}
]
Otherwise, it is an ordinary tag name, and a predicate is returned
that recognizes @racket[_element]s with that tag.
@examples[#:eval the-eval
((ntype?? '*) "blah")
((ntype?? '*) '(p "blah"))
((ntype?? '*text*) "blah")
((ntype?? '*text*) '(p "blah"))
]
}
@defproc[(ntype-namespace-id?? [ns-id (or/c string? #f)])
(-> any/c boolean?)]{
Returns a predicate that recognizes @racket[_element]s with tags
belonging to the namespace @racket[ns-id]. If @racket[ns-id] is
@racket[#f], the predicate recognizes elements whose tags have no
namespace.
@examples[#:eval the-eval
((ntype-namespace-id?? "atom") '(atom:id "blah"))
((ntype-namespace-id?? "atom") '(atomic "section"))
((ntype-namespace-id?? #f) '(atomic "section"))
]
}
@defproc[(sxml:node? [v any/c]) boolean?]{
Returns @racket[#t] for anything except an attribute list (that is,
a list whose first element is @racket['|@|]).
Note that the set of values accepted by @racket[sxml:node?] is
different from the non-terminal @racket[_node].
@examples[#:eval the-eval
(sxml:node? '(a (|@| (href "link.html")) "blah"))
(sxml:node? '(|@| (href "link.html")))
]
}
@defproc[(sxml:attr-list [node _node])
(listof _attribute)]{
If @racket[node] is an @racket[_element], returns its list of
attributes (or @racket['()]) if it has no attributes; for all other
types of @racket[_node], returns @racket['()].
@examples[#:eval the-eval
(sxml:attr-list '(a (|@| (href "link.html")) "blah"))
(sxml:attr-list '(p "blah"))
(sxml:attr-list "blah")
]
}
@;{ ============================================================ }
@;{ -- From sxml-tools.rkt -- }
@defproc[(sxml:attr-list-node [elem sxml:element?])
(or/c #f (cons/c '|@| (listof @#,racket[_attribute])))]{
Returns an element's attribute list node, or @racket[#f] it is has
none. Compare @racket[sxml:attr-list].
@examples[#:eval the-eval
(sxml:attr-list-node '(a (|@| (href "link.html")) "blah"))
(sxml:attr-list-node '(p "blah"))
]
}
@;{
sxml:attr-as-list
sxml:aux-list-node
sxml:aux-as-list
}
@defproc[(sxml:empty-element? [elem sxml:element?])
boolean?]{
Returns @racket[#t] if @racket[elem] has no nested elements, text
nodes, etc. The element may have attributes.
@examples[#:eval the-eval
(sxml:empty-element? '(br))
(sxml:empty-element? '(p "blah"))
(sxml:empty-element? '(link (|@| (rel "self") (href "here.html"))))
]
}
@;{
sxml:shallow-normalized?
sxml:normalized
sxml:shallow-minimized?
sxml:minimized?
sxml:name ;; what is domain???
}
@defproc[(sxml:element-name [elem sxml:element?])
symbol?]{
Returns an element's tag.
}
@defproc[(sxml:ncname [qualified-name symbol?])
string?]{
Returns the local part of a qualified name.
}
@defproc[(sxml:name->ns-id [qualified-name symbol?])
(or/c string? #f)]{
Returns the namespace part of a qualified name.
}
@defproc[(sxml:content [node-or-nodeset (or/c _node nodeset?)])
(listof _node)]{
Returns the contents (elements and text nodes) of an element or
nodeset.
}
@defproc[(sxml:text [node-or-nodeset (or/c _node nodeset?)])
string?]{
Returns a string consisting of all of the character data immediately
within @racket[node-or-nodeset].
@examples[#:eval the-eval
(sxml:text '(p (em "red") " fish; " (em "blue") " fish"))
]
}
@defproc[(sxml:attr [elem sxml:element?]
[attr-name symbol?])
(or/c string? #f)]{
Gets the value of the @racket[attr-name] attribute of @racket[elem].
}
@;{
sxml:content-raw
sxml:attr-list-u
sxml:aux-list
sxml:aux-list-u
sxml:aux-node
sxml:aux-nodes
sxml:attr-from-list
sxml:num-attr
sxml:attr-u
sxml:ns-list
sxml:ns-id->nodes
sxml:ns-id->uri
sxml:ns-uri->nodes
sxml:ns-id
sxml:ns-uri
sxml:ns-prefix
}
@defproc[(sxml:change-content [elem sxml:element?]
[new-content (listof _child)])
sxml:element?]{
Replaces the content of @racket[elem] with @racket[new-content],
preserving its attributes and auxiliary information.
}
@defproc[(sxml:change-attrlist [elem sxml:element?]
[new-attrlist (listof _attribute)])
sxml:element?]{
Replaces the attributes of @racket[elem] with @racket[new-attrlist],
preserving its contents and auxiliary information.
}
@defproc[(sxml:change-name [elem sxml:element?]
[tag symbol?])
sxml:element?]{
Changes the tag name of @racket[elem], preserving its attributes,
auxiliary information, and contents.
}
@defproc[(sxml:set-attr [elem sxml:element?]
[attr (list/c symbol? any/c)])
sxml:element?]{
Returns an element like @racket[elem] but with the attribute
@racket[attr], which replaces any existing attribute with
@racket[attr]'s key.
}
@defproc[(sxml:add-attr [elem sxml:element?]
[attr (list/c symbol? any/c)])
(or/c sxml:element? #f)]{
Like @racket[sxml:set-attr], but returns @racket[#f] if
@racket[elem] already contains an attribute with @racket[attr]'s
key.
}
@defproc[(sxml:change-attr [elem sxml:element?]
[attr (list/c symbol? any/c)])
(or/c sxml:element? #f)]{
Like @racket[sxml:set-attr], but returns @racket[#f] unless
@racket[elem] already contains an attribute with @racket[attr]'s
key.
}
@defproc[(sxml:squeeze [elem sxml:element?])
sxml:element?]{
Eliminates empty attribute lists and auxiliary lists.
}
@defproc[(sxml:clean [elem sxml:element?])
sxml:element?]{
Eliminates empty attribute lists and removes all auxilary lists.
}
@;{
sxml:add-aux
}
@;{ -- }
@;{
sxml:node-parent
sxml:lookup
sxml:attr->xml
sxml:string->xml
sxml:sxml->xml
sxml:attr->html
sxml:string->html
sxml:sxml->html
}