17

I'm looking for a solution that allows me to write native Emacs Lisp code and at compile time turns it into HTML, like Franz's htmlgen:

(html
 ((:div class "post")
  (:h1 "Title")
  (:p "Hello, World!")))

Of course I can write my own macros, but I'm interested if there are any projects around this problem.

Flux
  • 9,805
  • 5
  • 46
  • 92
viam0Zah
  • 25,949
  • 8
  • 77
  • 100
  • Why do you want it to be in Emacs Lisp, an antiquated dialect? You can easily interface with Common Lisp using SLIME, and then you could use htmlgen or yaclml or htout or LML(2) or CL-WHO or Scribble or ... – Jouni K. Seppänen Apr 28 '09 at 12:36
  • 1
    I use a framework written in Emacs Lisp that I'd like to extend with this HTML generating feature. It is tightly integrated with Emacs, that's why I'm looking for an Elisp solution. – viam0Zah Apr 28 '09 at 13:09

6 Answers6

6

As you found out, xmlgen generates XML from a list structure. What I did find disappointing with the ``xmlgen` package that the format it supports is not quite the inverse of Emacs' xml parser.

I did add this to my copy of xmlgen:

;; this creates a routine to be the inverse of what xml-parse does
;;;###autoload
(defun xml-gen (form &optional in-elm level)
  "Convert a sexp to xml:
  '(p :class \"big\")) => \"<p class=\\\"big\\\" />\""
  (let ((level (or level 0)))
    (cond
     ((numberp form) (number-to-string form))
     ((stringp form) form)
     ((listp form)
      (destructuring-bind (xml attrs) (xml-gen-extract-plist form)
        (let ((el (car xml)))
          (unless (symbolp el)
            (error "Element must be a symbol (got '%S')." el))
          (setq el (symbol-name el))
          (concat "<" el (xml-gen-attr-to-string attrs)
                  (if (> (length xml) 1)
                      (concat ">" (mapconcat
                                   (lambda (s) (xml-gen s el (1+ level)))
                                   (cdr xml)
                                   "")
                              "</" el ">")
                    "/>"))))))))

(defun xml-gen-attr-to-string (plist)
  (reduce 'concat (mapcar (lambda (p) (concat " " (symbol-name (car p)) "=\"" (cdr p) "\"")) plist)))

(defun xml-gen-extract-plist (list)
  (list (cons (car list) (let ((kids (xml-node-children list)))
                           (if (= 1 (length kids))
                               kids
                             (remove-if-not 'listp kids))))
        (xml-node-attributes list)))

Note: the interface for this is xml-gen (not xmlgen which is the original parsing).

With this interface, the following holds:

(string-equal (xml-gen (car (xml-parse-region <some-region-of-xml>)))
              <some-region-of-xml>)

and

(equal (car (xml-parse-region (insert (xml-gen <some-xml-form>))))
       <some-xml-form>)

The new xml-gen does not strive to preserve the whitespace around that the xml-parse-region routine generates.

Community
  • 1
  • 1
Trey Jackson
  • 73,529
  • 11
  • 197
  • 229
2

This could be a starting point: http://www.emacswiki.org/emacs/HtmlLite

js.
  • 1,787
  • 19
  • 22
  • 1
    Thanks, this is useful, too. My only problem with it that it pollutes the namespace with many functions instead of using a macro. – viam0Zah Apr 29 '09 at 07:00
1

I had a similar requirement to be able to parse xml using xml-parse functions, transform it, and then output it back as a xml string.

Trey's solution almost worked except I needed to retain the whitespace xml elements. So I wrote my own implementation here:

https://github.com/upgradingdave/xml-to-string

Upgradingdave
  • 12,916
  • 10
  • 62
  • 72
1

This is not quite what you're looking for, but there's a 20 minute video where a guy creates a simple website using UCW, the UnCommon Web application framework. It's all done in Emacs using lisp...

Here is a link to the transcript (all the code (~25 lines) is available at the end of the transcript).

Trey Jackson
  • 73,529
  • 11
  • 197
  • 229
  • Thanks, but that's really not what I'm looking for. I've got an existing Elisp framework that has some HTML generating facilities—currently with hard-coded HTML strings I'd like to replace. – viam0Zah Apr 28 '09 at 14:16
1

Meanwhile, I found some code that contains something similar I want. Now I can write:

(views-with-html
 ((body)
  (h1 "Title")
  ((p (class . "entry")) "Hello, World!")))

The implementation has a few limitations (e.g. hard-coded element list), but it seems to be a good starting point.

viam0Zah
  • 25,949
  • 8
  • 77
  • 100
0

Have you considered yaclml? yaclml (Yet Another Common Lisp Markup Language) is an HTML generator and HTML template library. yaclml is used as the html templating backend for the ucw web framework. https://www.cliki.net/yaclml

It is in common lisp. Not elisp. But, ...

Mohsen Banan
  • 85
  • 1
  • 5
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/30410456) – Sfili_81 Nov 24 '21 at 16:11