#lang typed/racket/base/no-check ;;; @Package xexp ;;; @Subtitle SXML/xexp Representation of XML and HTML in Racket ;;; @HomePage http://www.neilvandyke.org/racket-xexp/ ;;; @Author Neil Van Dyke ;;; @Version 0.1 ;;; @Date 2011-08-21 ;;; @PLaneT neil/xexp:1:=0 ;; $Id: xexp.rkt,v 1.27 2011/08/22 04:52:47 neilpair Exp $ ;;; @legal ;;; Copyright @copyright{} 2011 Neil Van Dyke. This program is Software; ;;; you can redistribute it and/or modify it under the terms of the GNU Lesser ;;; General Public License as published by the Free Software Foundation; either ;;; version 3 of the License (LGPL 3), or (at your option) any later version. ;;; This program is distributed in the hope that it will be useful, but without ;;; any warranty; without even the implied warranty of merchantability or ;;; fitness for a particular purpose. See ;;; @indicateurl{http://www.gnu.org/licenses/} for details. For other licenses ;;; and consulting, please contact the author. ;;; @end legal ;;; @section Introduction ;;; @i{Note: This package is in a state of active development, and some ;;; interface changes, perhaps not backward-compatible, are expected. ;;; Documentation is gravely lacking.} ;;; @uref{http://pobox.com/~oleg/ftp/Scheme/SXML.html, SXML} is a ;;; representation for XML in Scheme, defined by Oleg Kiselyov. ;;; ``SXML/@i{xexp}'' is the temporary name for a format for Racket that's ;;; based on SXML and is mostly compatible with it. The current plan is, ;;; hopefully, for the ``/@i{xexp}'' part of the name to go away, and for SXML ;;; and @i{xexp} to merge. For now, Racket language identifiers based on ;;; SXML/@i{xexp} will have ``@code{xexp}'' instead of ``@code{sxml}'', because ;;; we do not want to call something ``SXML'' if it is not strictly SXML. ;;; (And, historically, @i{xexp} was much more different from SXML, while we ;;; experimented with unifying SXML, SHTML, and PLT @i{xexpr}, but we have ;;; decided to move back to as compatible with SXML as practical.) This ;;; documentation will be fleshed out in a later version of the SXML/@i{xexpr} ;;; tools. ;; TODO: !!! Incorporate bits of this documentation for SHTML, as appropriate. ;; ;; @subsection Differences with SXML ;; @i{xexp} can be defined as differences from SXML: ;; ;; @itemize ;; ;; @item ;; @i{xexp} is intended for representing HTML, including XHTML, but not XML in ;; general. ;; ;; @item ;; When used to represent HTML, element names are all lower-case, even when ;; used to represent a version of HTML that is not case-sensitive. ;; ;; @item ;; @i{xexp} syntax must be ordered as in SXML first normal form (1NF). For ;; example, any attributes list must precede child elements. @i{xexp} tools ;; @i{may} be permissive about accepting other orderings, but @i{must not} emit ;; any ordering but 1NF ordering. ;; ;; @item ;; @i{xexp} elements do not have namespace qualifiers. @i{xexp} tools @i{may} accept ;; qualifiers, but are not required to, and should not emit @i{xexp} with ;; qualifiers. ;; ;; @item ;; The SXML keyword symbols, such as @code{*TOP*}, are defined to be in ;; all-uppercase, regardless of the case-sensitivity of the reader of the ;; hosting Scheme implementation in any context. ;; ;; @item ;; @i{xexp} adds a special @code{&} syntax for non-ASCII characters. This is ;; because not all character entity references used in HTML can be converted ;; to Scheme characters in all R5RS Scheme implementations, nor represented in ;; conventional text files or other common external text formats to which one ;; might wish to write @i{xexp}. The syntax is @code{(& @var{val})}, where ;; @var{val} is the symbolic name of the character as a symbol or string, or ;; an integer with the numeric value of the character. ;; ;; @end itemize ;; ;; @i{xexp} was defined originally as SHTML in ;; @uref{http:/www.neilvandyke.org/htmlprag/, HtmlPrag} 0.11 (2004-05-13). ;; HtmlPrag used an SXML subset since its first public release on 2003-01-31. ;; Earlier, unreleased versions of HtmlPrag used a representation closer to ;; that currently used by some PLT Scheme standard libraries. ;; ;; @subsection Differences of xexp from SHTML ;; ;; !!! #t is no longer a valid attribute value ;;; @section xexp and SXML Tools ;;; ;;; Libraries using @i{xexp} include: ;;; ;;; @table @asis ;;; ;;; @item @uref{http://www.neilvandyke.org/racket-html-parsing/, html-parsing} ;;; Permissively parsing HTML to @i{xexp}. ;;; ;;; @item @uref{http://www.neilvandyke.org/racket-html-writing/, html-writing} ;;; Writing HTML from @i{xexp}. ;;; ;;; @item @uref{http://www.neilvandyke.org/racket-html-template/, html-template} ;;; Writing HTML from @i{xexp} templates. ;;; ;;; @item @uref{http://www.neilvandyke.org/webscraperhelper/, WebScraperHelper} ;;; Example-based SXPath query generation for @i{xexp}. ;;; ;;; @end table ;;; ;;; @noindent ;;; There are also libraries for SXML, which generally can be used for @i{xexp}: ;;; ;;; @table @asis ;;; ;;; @item @uref{http://okmij.org/ftp/Scheme/xml.html#SXPath, SXPath} ;;; XPath query language implementation for SXML, by Oleg Kiselyov. ;;; ;;; @item @uref{http://celtic.benderweb.net/sxml-match/, sxml-match} ;;; Pattern-matching of SXML, by Jim Bender. ;;; ;;; @item @uref{http://www196.pair.com/lisovsky/xml/ssax/, SSAX} ;;; Parsing of XML to SXML, by Oleg Kiselyov, and maintained by Kirill Lisovsky. ;;; ;;; @end table ;;; @section Definitions ;;; Some definitions used by many SXML/@i{xexp} packages... ;;; @subsection Exceptions ;; Note: These are here for future expansion. For example, we might want to ;; give positional information from metadata. (struct: exn:fail:invalid-xexp exn:fail ((expected : String) (context-xexp : Any) (invalid-xexp : Any)) #:transparent) ;;; @defproc make-invalid xexp-exc ;;; ;;; !!! (define (make-invalid-xexp-exc sym #:continuation-marks continuation-marks #:expected expected #:invalid-xexp invalid-xexp #:context-xexp (context-xexp (void))) (exn:fail:invalid-xexp (if (void? context-xexp) (format "~A: invalid xexp: expected ~A; got ~S" sym expected invalid-xexp) (format "~A: invalid xexp: expected ~A; got ~S in ~S" sym expected invalid-xexp context-xexp)) continuation-marks expected context-xexp invalid-xexp)) ;;; @defproc raise-invalid-xexp-error ;;; ;;; !!! (define-syntax raise-invalid-xexp-error (syntax-rules () ((_ SYM #:expected EXPECTED #:invalid-xexp INVALID-XEXP #:context-xexp CONTEXT-XEXP) (raise (make-invalid-xexp-exc SYM #:continuation-marks (current-continuation-marks) #:expected EXPECTED #:invalid-xexp INVALID-XEXP #:context-xexp CONTEXT-XEXP))) ((_ SYM #:expected EXPECTED #:invalid-xexp INVALID-XEXP) (raise-invalid-xexp-error SYM #:expected EXPECTED #:invalid-xexp INVALID-XEXP #:context-xexp (void))))) ;;; @subsection Misc. ;;; The following definitions are used by some @i{xexp}-related libraries. (define-type Xexp Any) ;; @defvar xexp-comment-symbol ;; @defvarx xexp-pi-symbol ;; @defvarx xexp-top-symbol ;; @defvarx xexp-decl-symbol ;; ;; These variables are bound to the following case-sensitive symbols used in ;; @i{xexp}, respectively: @code{*COMMENT*}, @code{*DECL*}, @code{*EMPTY*}, ;; @code{*END*}, @code{*ENTITY*}, @code{*PI*}, @code{*START*}, @code{*TEXT*}, ;; and @code{*TOP*}. These can be used in lieu of the literal symbols in ;; programs read by a case-insensitive Scheme reader. (Note: Scheme ;; implementators who have not yet made @code{read} case-sensitive by default ;; are encouraged to do so.) ;;(define xexp-comment-symbol '*COMMENT*) ;;(define xexp-decl-symbol '*DECL*) ;;(define xexp-pi-symbol '*PI*) ;;(define xexp-top-symbol '*TOP*) ;;(define xexp-splice-symbol '*SPLICE*) ;; (define-type XexpNamedCharRef (Pair '& (Pair Any Any))) ;; @defvar xexp-named-char-id ;; @defvarx xexp-numeric-char-id ;; ;; These variables are bound to the @i{xexp} entity public identifier strings ;; used in SXML @code{*ENTITY*} named and numeric character entity ;; references. ;; (define xexp-named-char-id "xexp-named-char") ;; (define xexp-numeric-char-id "xexp-numeric-char") ;;; @defproc make-xexp-char-ref val ;;; ;;; Yields an @i{xexp} character entity reference for @var{val}. For example: ;;; ;;; @lisp ;;; (make-xexp-char-ref "rArr") @result{} (& rArr) ;;; (make-xexp-char-ref (string->symbol "rArr")) @result{} (& rArr) ;;; (make-xexp-char-ref 151) @result{} (& 151) ;;; @end lisp (: make-xexp-char-ref (Symbol -> XexpNamedCharRef)) (define (make-xexp-char-ref val) (list '& (cond ((symbol? val) val) ;; ((integer? val) val) ;; ((string? val) (string->symbol val)) (else (error 'make-xexp-char-ref "invalid xexp reference value: ~S" val))))) ;; TODO: ;; ;; (define (xexp-entity? x) ;; (and (xexp-char-ref-value entity) #t)) ;;; @defproc xexp-char-ref-value obj ;;; ;;; Yields the value for the @i{xexp} entity @var{obj}, or @code{#f} if @var{obj} ;;; is not a recognized entity. Values of named entities are symbols, and ;;; values of numeric entities are numbers. An error may raised if @var{obj} ;;; is an entity with system ID inconsistent with its public ID. For example: ;;; ;;; @lisp ;;; (define (f s) (xexp-char-ref-value (cadr (html->xexp s)))) ;;; (f " ") @result{} nbsp ;;; (f "ߐ") @result{} 2000 ;;; @end lisp ;; TODO: !!! rename to xexp-reference-SOMETHING (where SOMETHING is idealy ;; whatever the XML grammar calls it) (: %find-first-xexp-non-extraneous-list (Any -> Any)) (define (%find-first-xexp-non-extraneous-list lst) (let loop ((lst lst)) (: loop (Any -> Any)) (cond ((null? lst) #f) ((pair? lst) (loop (car lst)) (loop (cdr lst))) (else lst)))) (: %assert-only-xexp-extraneous-lists (Any -> Void)) (define (%assert-only-xexp-extraneous-lists lst) (cond ((%find-first-xexp-non-extraneous-list lst) => (lambda (x) (raise-invalid-xexp-error '%assert-only-xexp-extraneous-lists #:expected "nothing except extraneous lists and nulls" #:invalid-xexp x))))) (: xexp-char-ref-value (XexpNamedCharRef -> Symbol)) (define (xexp-char-ref-value char-ref) (or (let: loop-find-symbol : (U Symbol False) ((lst : Any (cdr char-ref))) (cond ((null? lst) #f) ((pair? lst) (let ((head (car lst))) (cond ((symbol? head) (%assert-only-xexp-extraneous-lists (cdr lst)) head) ((pair? head) (cond ((loop-find-symbol head) => (lambda (found) (%assert-only-xexp-extraneous-lists (cdr head)) (%assert-only-xexp-extraneous-lists (cdr lst)) found)) ((loop-find-symbol (cdr head)) => (lambda (found) (%assert-only-xexp-extraneous-lists (cdr lst)) found)) (else (loop-find-symbol (cdr lst))))) ((null? head) (loop-find-symbol (cdr lst))) (else (raise-invalid-xexp-error 'xexp-char-ref-value #:expected "char-ref body" #:invalid-xexp head #:context-xexp char-ref))))) (else (raise-invalid-xexp-error 'xexp-char-ref-value #:expected "proper list in char-ref body" #:invalid-xexp lst #:context-xexp char-ref)))) (raise-invalid-xexp-error 'xexp-char-ref-value #:expected "char-ref" #:invalid-xexp char-ref))) ;; TODO: !!! CLEAN UP THIS LOGIC, AND ALSO DECIDE WHETHER THE PUBLIC/SYSTEM ;; STUFF IS NEEDED ;; (cond ;; ((not (pair? entity)) #f) ;; ((null? (cdr entity)) #f) ;; ((eqv? (car entity) '&) ;; TODO: Error-check for extraneous list members? ;; (let ((val (cadr entity))) ;; (cond ((symbol? val) val) ;; ((integer? val) val) ;; !!! ((string? val) (string->symbol val)) ;; (else #f)))) ;;((eqv? (car entity) '*ENTITY*) ;; (if (null? (cddr entity)) ;; #f ;; (let ((public-id (list-ref entity 1)) ;; (system-id (list-ref entity 2))) ;; ;; TODO: Error-check for extraneous list members? ;; (cond ((equal? public-id xexp-named-char-id) ;; (string->symbol system-id)) ;; ((equal? public-id xexp-numeric-char-id) ;; (string->number system-id)) ;; (else #f))))) ;; (else #f))) ;; @defvar always-empty-html-elements ;; ;; List of symbols for names of HTML elements that can never have content. ;; For example, the @code{br} element. ;; TODO: !!! move this to html-specific, shared by "html-parsing" and ;; "html-writing". (define always-empty-html-elements '(area base br frame hr img input isindex keygen link meta object param spacer wbr)) ;; @section !!! DETAILED GRAMMAR ;; Requirements of Scheme implementation: ;; * R5RS ;; * Unicode character support ;; * case-sensitive reader (recommended for examples) ;; !!! hexp will be superset of xexp. ;; !!! sxml: too many normal forms. too many variations. doesn't cover ;; everything. verbose. ;; [XML] W3C, ``Extensible Markup Language (XML) 1.1 (Second Edition),'' ;; 2006-08-16, @url{http://www.w3.org/TR/2006/REC-xml11-20060816/} ;; TODO: Find XML test suites, and use them. ;; | 2.1 Well-Formed XML Documents ;; | Document ;; | [1] document ::= ( prolog element Misc* ) - ( Char* RestrictedChar Char* ) ;; !!! ;; | 2.2 Characters ;; | [Definition: A parsed entity contains text, a sequence of characters, ;; | which may represent markup or character data.] [Definition: A character is ;; | an atomic unit of text as specified by ISO/IEC 10646 [ISO/IEC ;; | 10646]. Legal characters are tab, carriage return, line feed, and the ;; | legal characters of Unicode and ISO/IEC 10646. The versions of these ;; | standards cited in A.1 Normative References were current at the time this ;; | document was prepared. New characters may be added to these standards by ;; | amendments or new editions. Consequently, XML processors MUST accept any ;; | character in the range specified for Char.] ;; | Character Range ;; | [2] Char ::= [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */ ;; | [2a] RestrictedChar ::= [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F] ;; | The mechanism for encoding character code points into bit patterns may ;; | vary from entity to entity. All XML processors MUST accept the UTF-8 and ;; | UTF-16 encodings of Unicode [Unicode]; the mechanisms for signaling which ;; | of the two is in use, or for bringing other encodings into play, are ;; | discussed later, in 4.3.3 Character Encoding in Entities. ;; | Note: ;; | Document authors are encouraged to avoid "compatibility characters", as ;; | defined in Unicode [Unicode]. The characters defined in the following ;; | ranges are also discouraged. They are either control characters or ;; | permanently undefined Unicode characters: ;; | [#x1-#x8], [#xB-#xC], [#xE-#x1F], [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF], ;; | [#x1FFFE-#x1FFFF], [#x2FFFE-#x2FFFF], [#x3FFFE-#x3FFFF], ;; | [#x4FFFE-#x4FFFF], [#x5FFFE-#x5FFFF], [#x6FFFE-#x6FFFF], ;; | [#x7FFFE-#x7FFFF], [#x8FFFE-#x8FFFF], [#x9FFFE-#x9FFFF], ;; | [#xAFFFE-#xAFFFF], [#xBFFFE-#xBFFFF], [#xCFFFE-#xCFFFF], ;; | [#xDFFFE-#xDFFFF], [#xEFFFE-#xEFFFF], [#xFFFFE-#xFFFFF], ;; | [#x10FFFE-#x10FFFF]. ;; | 2.3 Common Syntactic Constructs ;; | White Space ;; | [3] S ::= (#x20 | #x9 | #xD | #xA)+ ;; TODO: Make this right for XML 1.0 too. (define %xexp:char-x20 (integer->char #x20)) (define %xexp:char-x9 (integer->char #x9)) (define %xexp:char-xa (integer->char #xa)) (define %xexp:char-xd (integer->char #xd)) (define %xexp:whitespace-char-list (list %xexp:char-x20 %xexp:char-x9 %xexp:char-xa %xexp:char-xd)) (define (%xexp:whitespace-char? c) (memv c %xexp:whitespace-char-list)) ;; PI ::= (? PI-TARGET [* [| STRING (SYMBOL [+ STRING ] ) ] ] ) ;; ;; PI-TARGET ::= SYMBOL ;;CDSECT ::= (!cdata [* STRING ] ) ;;(!cdata "<greeting>Hello, world!</greeting>") ;;(? xml (version "1.1")) ;;(greeting "Hello, world!") ;;PROLOG ::= XML-DECL [* MISC ] [? doctypedecl [* MISC ] ] ;;XML-DECL ::= (? xml VERSION-INFO [? ENCODINGDECL ] [? SD-DECL ] ) ;;VERSION-INFO ::= (version [| "1.0" "1.1" ] ) ;;MISC ::= [| COMMENT PI ] ;;DOCTYPEDECL ::= (!doctype NAME [? EXTERNAL-ID ] [? INT-SUBSET ] ) ;;EXTERNAL-ID ::= [| (system SYSTEM-LITERAL) ;; (public PUBID-LITERAL SYSTEM-LITERAL) ] ;;INT-SUBSET ::= (internal [* [| MARKUP-DECL DECL-SEP ] ]) ;;DECL-SEP ::= PE-REFERENCE ;; ;;MARKUP-DECL ::= [| ELEMENT-DECL ATTLIST-DECL ENTITY-DECL NOTATION-DECL PI COMMENT ] ;;EXT-SUBSET ::= [? TEXT-DECL ] EXT-SUBSET-DECL ;;EXT-SUBSET-DECL ::= [* [| MARKUP-DECL CONDITIONAL-SECT DECL-SEP ] ] ;;(? xml (version "1.1")) ;;(!doctype greeting SYSTEM "hello.dtd") ;;(greeting "Hello, world!") ;;(? xml (version "1.1") (encoding "UTF-8")) ;;(!doctype greeting ((!ELEMENT greeting (PCDATA)))) ;;(greeting "Hello, world!") ;; SD-DECL ::= (standalone [| "yes" "no" ] ) ;;(? xml (version "1.1") (standalone "yes")) ;;(!attlist poem xml:space (default preserve) "preserve") ;;(!attlist pre xml:space (preserve) fixed "preserve") ;;(p ((xml:lang "en")) "The quick brown fox jumps over the lazy dog.") ;;(p ((xml:lang "en-GB")) "What colour is it?") ;;(p ((xml:lang "en-US")) "What color is it?") ;;(sp ((who "Faust") (desc "leide") (xml:lang "de")) ;; (l "Habe nun, ach! Philosophie,") ;; (l "Juristerei, und Medizin") ;; (l "und leider auch Theologie") ;; (l "durchaus studiert mid hei" #xdf "em Bem" #xfc "h'n.")) ;;(!attlist poem xml:lang CDATA "fr") ;;(!attlist gloss xml:lang CDATA "en") ;;(!attlist note xml:lang CDATA "en") ;; ELEMENT ::= ( NAME [? ( [* ATTRIBUTE ] ) ] ) ;; ATTRIBUTE ::= (NAME [* ATTR-VALUE-PART ] ) ;;(!attlist termdef ;; (id id #REQUIRED) ;; (name cdata #IMPLIED)) ;;(!attlist list ;; (type (| bullets ordered glossary) ordered)) ;;(!attlist form ;; (method cdata #FIXED "POST")) ;;(!-- "declare the parameter entity \"ISOLat2\"...") ;;(!entity % ISOLat2 SYSTEM "http://www.xml.com/iso/isolat2-xml.entities") ;;(!-- "... now reference it.") ;;(% ISOLat2) ;; | 4.2 Entity Declarations ;; (!entity Pub-Status "This is a pre-release of the specification.") ;; | 4.2.2 External Entities ;;(!entity open-hatch ;; SYSTEM ;; "http://www.textuality.com/boilerplate/OpenHatch.xml") ;;(!entity open-hatch ;; PUBLIC ;; "-//Textuality//TEXT Standard open-hatch boilerplate//EN" ;; "http://www.textuality.com/boilerplate/OpenHatch.xml") ;;(!entity hatch-pic SYSTEM "../grafix/OpenHatch.gif" NDATA gif) ;; | 4.3 Parsed Entities ;; | 4.3.1 The Text Declaration ;; (? xml VERSION-INFO ENCODING-DECL) ;; --------------------- ;; document ;; ;; prolog ;; element ;; misc* ;; ;; ;; http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-prolog-dtd ;; ;; (?xml version STRING [ encoding STRING ] [ standalone BOOL ] ) ;; ;; (!doctype NAME [ EXTERNAL-ID ] [ ( INT-SUBSET ) ] ) ;; ;; EXTERNAL-ID ::= system SYSTEM-LITERAL ;; | public PUBID-LITERAL SYSTEM-LITERAL ;; ;; SYSTEM-LITERAL ::= STRING ;; ;; PUBID-LITERAL ::= STRING ;; ;; ;; http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-cdata-sect ;; ;; (!cdata [ STRING ]+ ) ;; ;; (!-- [ STRING ]+ ) ;; ;; ;; (!entity % draft 'INCLUDE') ;; (!entity % final 'IGNORE') ;; ;; ;; http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-condition-sect ;; ;; (!% draft [ XEXP ]+ ) ;; (!% final [ XEXP ]+ ) ;; ;; (!% draft ;; (!element book ((* comments) title body (? supplements)))) ;; ;; (!% final ;; (!element book (title body (? supplements)))) ;; ;; ;; ;; 4.1 Character and Entity References ;; ;; http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-references ;; ;; CharRef ;; 42 #x42 ;; ;; ;; EntityRef ;; nbsp ;; copy ;; ;; PEReference ;; (% !!!) ;; ;; (!entity NAME ENTITYDEF) ;; (!entity % NAME PEDEF) ;; ;; (!entity Pub-Status "This is a pre-release of the specification.") ;; ;; ;; 4.5 Construction of Entity Replacement Text ;; ;; (!entity % pub #xC9 "ditions Gallimard") ;; (!entity rights "All rights reserved") ;; (!entity book "La Peste: Albert Camus, " #xA9 " 1947 " (% pub) ". " rights) ;; ;; ;; ;; 4.6 Predefined Entities ;; ;; (!entity lt #x38 #x60) ;; (!entity gt #x62) ;; ;; ;; 4.7 Notation Declarations ;; ;; (!notation NAME EXTERNAL-ID-OR-PUBLIC-ID) ;; ;; PUBLIC-ID ::= public PUBID-LITERAL ;; ;; ;; ;; ;; (?splice ...) used to write multiple elements at once when only one xexp is ;; ;; expected. and to efficiently incorporate large content lists. ;; ;; ;;; @section Introduction ;; ;; ;; ;; (define (xexp-elem-name elem) ;; ;; ) ;; ;; (define (xexp-elem-attrs elem) ;; ;; ) ;; ;; (define (xexp-elem-content elem) ;; ;; ) ;; ;; (define (sxml->xexp sxml) ;; '!!!) ;; ;; (define (xexp->xexp xexp) ;; '!!!) ;;; @unnumberedsec History ;;; @table @asis ;;; ;;; @item Version 0.1 --- 2011-08-21 --- PLaneT @code{(1 0)} ;;; Part of forked development from HtmlPrag. ;;; ;;; @end table (provide ;; types ;; Xexp ;; variables and syntax raise-invalid-xexp-error exn:fail:invalid-xexp? always-empty-html-elements make-xexp-char-ref xexp-char-ref-value raise-invalid-xexp-error)