Find file
Fetching contributors…
Cannot retrieve contributors at this time
89 lines (78 sloc) 3.7 KB
;; @module Element
;; @author Jeff Ober <>, Kanen Flowers <>
;; @version 1.0
;; @location
;; @package
;; @description A simple way of generating valid XML content (requires newlisp 10).
;; Often, XML modules attempt to provide everything but the kitchen sink when
;; all that you <really> want is to write valid XML simply and quickly. Element
;; is a purely practical module that lets you write XML fast and efficiently. It
;; performs no validation and does nothing apart from serialize data to XML. If
;; you need extra functionality like indentation or serialization of SXML, look
;; at the XML module.
;; <h4>Version history</h4>
;; <b>1.0</b>
;; &bull; initial release
;; <h4>Bugs and todos</h4>
;; &bull; XML declaration function with encoding
(context 'Element)
(constant 'xml-entity-encode-re (regex-comp (string "(" (join (map (fn (i) (format {\x%x} i)) '(34 38 39 60 62)) "|") ")")))
;; @syntax (Element:encode <str>)
;; @param <str> a string
;; <p>Encodes characters in a string to be valid for XML.</p>
(define (encode str)
(replace xml-entity-encode-re (string str) (string "&#" (char $1) ";") 0x10000))
(define (serialize-attributes attributes)
((list? attributes) (join (map (fn (pair) (format " %s=\"%s\"" (map encode pair))) attributes) ""))
((string? attributes) (string " " attributes))
(true "")))
(define (opening-tag tag attributes)
(string "<" tag (serialize-attributes attributes) ">"))
(define (closing-tag tag)
(string "</" tag ">"))
(define (empty-tag tag attributes)
(string "<" tag (serialize-attributes attributes) " />"))
;; @syntax (Element:Element <str-tag> <attributes> [<str-content> ...])
;; @param <str-tag> the tag name
;; @param <attributes> an association list of key/value pairs, a string, or nil
;; @param <str-content> any number of strings
;; <p>Builds an element tag with the name <str-tag> and attributes <attributes>
;; around the content <str-content>, which generally is also built using this
;; function. If <attributes> is an association list, it is converted to a series
;; of key="value" pairs. If it is a string, it is inserted as-is. Otherwise, it
;; is ignored. <str-content> may be strings generated by XmlBuilder:element or
;; otherwise (in which case it is inserted as text content). Attribute values are
;; encoded as needed (if an association list); <str-content> must be encoded if
;; a text value.</p>
;; @example
;; (Element "div" '(("class" "content"))
;; (Element "h2" nil (Element:encode "Welcome"))
;; (Element "p" {class="message"} (Element:encode "Hello world.")))
;; => <div class="content"><h2>Welcome</h2><p class="message">Hello world.</p></div>
(define (Element:Element tag attributes)
(if (empty? (args))
(empty-tag tag attributes)
(opening-tag tag attributes)
(join (map (fn (a)
(if (list? a)
(join (map string a))
(string a)))
(closing-tag tag))))
;; @syntax (Element:doc <str-encoding> [<str-content> ...])
;; @param <str-encoding> encoding for XML declaration
;; @param <str-content> any number of strings
;; <p>Adds an XML declaration to a string. If encoding is nil, defaults to UTF-8
;; when newlisp is compiled with UTF-8 support, ASCII otherwise.</p>
;; @example
;; (Element:doc "UTF-8" (Element "root" nil "Hello world."))
;; =>
;; <?xml version="1.0" encoding="UTF-8" ?>
;; <root>Hello world.</root>
(define (doc encoding)
(unless encoding (setq encoding (if utf8 "UTF-8" "ASCII")))
(string {<?xml version="1.0" encoding="} encoding {" ?>} "\n" (join (map string (args)))))
(context 'MAIN)