Messing Around With SXML

May 14, 2020

I've been interested in SXML for a while. I just finished writing my own image gallery generator using SXML, and I have to admit... Guile doesn't exactly have amazing SXML documentation, so I decided to write a bit about it.


What's SXML?

SXML, or "Symbolic XML" is a lispy, and dare I say, more intuitive way of writing XML documents. For example, instead of writing the following snippit in XML:

<bird>
 <type>Chickadee</type>
 <name>Joe</name>
</bird>

You could simply write the following SXML expression:

(bird
 (type Chickadee)
 (name Joe))

If you take a look at the above snippits, you'll realize that SXML is very much like XML. You just don't need explicit closing tags for SXML. This comes naturally to Lisp and it would be nice if XML was like this to begin with, but that's okay.

One problem with SXML though, is the documentation. Every implementation is a little different, and since it's not exactly a hot topic, not a lot of people are writing about it.


Getting Started

I'm going to use the (sxml simple) module in Guile Scheme, which comes with plenty of tools to help us get comfortable with SXML.

We'll start off by writing a "Hello world" XML document to a file.

(use-modules (sxml simple))
(let ((port (open-output-file "test.xml")))
 (sxml->xml '(p "Hello world!") port)
 (close-port port))

In this example we define "port", which is a file named "test.xml". (sxml->xml) lets us specify the port we write to, so we tell SXML to write to our file.

test.xml should now caontain the line '<p>Hello world!</p>'. You can also transform XML to SXML with '(xml->sxml)'.

Because SXML is really just XML, all you need to know are the oddities and differences of SXML. For example, attributes in SXML are different:

(bird
 (@ (type Chickadee)
    (name Joe)))
;; <bird type="Chickadee" name="Joe">

honestly, I think it would have been better if attributes were Guile tags instead, for example:

;; Incorrect code. This will not run
(bird
 #:type Chickadee
 #:name Joe)

I don't know how Guile tags work on a low level, though, so I can't complain.


Abstractions

Because Guile's SXML module is part of Guile, you can use the power of Guile to make your life easier through abstractions!

For example, You can use Scheme variables in SXML if you use a backquote (`)

(define name "Jimbo")
(sxml->xml
`(p "Hey there, ",name)
;; <p>Hey there, Jimbo</p>

Variables can come in handy when you want your user to be able to customize a lot of things!

(define me
 '((name "Spongebob")
   (title "My Work Blog")
   (message "Welcome to my website!")
   (best-friend "Patrick")))

You could then use association lists for every sublist defined in 'me'!

I tend to use custom functions as shortcuts for myself, so I don't need to write out loooong strings of SXML all the time:

(define (a string link)
 `((a (@ (href ,link)) ,string)))

;; Now instead of writing *this* all the time:
(a (@ (href "https://muto.ca")) "My site!")

;; I can just slap down:
,(a "My site!" "https://muto.ca")

I know I'm taking this a bit far, but I like abstraction, so let's continue.

You can create a post template for all your files, and create new files based on it easily:

(define (post title date body)
 (let ((port (open-output-port "post.html")))
  (display
   (string-append
    "<!DOCTYPE html>\n"
    "<html>\n"
    "<head>\n"
    "<title>" title "</title>\n"
    "</head>\n"
    "<body>\n"
    "<h1>" title "</h1>\n"
    "<h2>" date "</h2>\n") port)
    (sxml->xml ,body port)
  (display
   (string-append
    "</body>\n"
    "</html>") port)))

We can use this function like so:

(post "My Test Post" "May 14, 2020"
 '((p "Hello and thanks for checking out this blog post!")))

Conclusion

I enjoy writing in SXML, although I wish it had a standard design. Every implementation is a little different. For example, Guile's SXML doesn't include support for <!-- comments -->, so I had to modify the existing module just so I could have comments!

I still need to get used to SXML. I really enjoy it and I feel that, with enough time and the right abstractions, I could have a blast with this little module!

Anyway, since this post may leave you wanting more, Here's a list of resources that could help you find your way in the mystical world of SXML: