Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 477
  • Last Modified:

lisp: named parameters for structured data - lisp to xml conversion

Here's my simple LISP program for converting structured data to XML:

(defun strcat (&rest args)
  (apply #'concatenate
    (cons 'string args)))

(defun rectangle (x y width height color &rest children)
      " x='" (princ-to-string x) "'"
      " y='" (princ-to-string y) "'"
      " width='" (princ-to-string width) "'"
      " height='" (princ-to-string height) "'"
      " color='" (princ-to-string color) "'"
    (apply #'strcat children)

  (rectangle 0 0 10 20 "blue"
    (rectangle 1 1 3 4 "green")
    (rectangle 5 1 3 4 "red")

Here's the output:

"<rectangle x='0' y='0' width='10' height='20' color='blue'><rectangle x='1' y='1' width='3' height='4' color='green'></rectangle><rectangle x='5' y='1' width='3' height='4' color='red'></rectangle></rectangle>"

However, I'd rather want the LISP program to use named parameters like this:

  (rectangle x: 0 y: 0 width: 10 height: 20 color: "blue"
    (rectangle x: 1 y: 1 width: 3 height: 4 color: "green")
    (rectangle x: 5 y: 1 width: 3 height: 4 color: "red")

Sort-of like as described on

  (button label: "Back"
          image: left-arrow
          oncommand: back-command)
  (button label: "Next"
          image: right-arrow
          oncommand: next-command))

I've tried using "&key" in common lisp, but using it seems to require that all (not some) parameters be named.  Example:

  (defun foo (&rest rest &key a b c) (list rest a b c))
  (print (foo :a 1 :b 2 :c 3 1 2 3))

output error:

  *** - FOO: keyword arguments in (:A 1 :B 2 :C 3 1 2 3) should occur pairwise

I can do this:

  (defun foo (&rest rest) (list rest))
  (print (foo :a 1 :b 2 :c 3 1 2 3))

But, how does one bind and use the named parameters as in the original program.  Is there a convention for this?  Am I even on the right track?

Also, what is the difference between ":x" and "x:"?  The latter "looks" better in my code (the colon separates the attribute key and value), but the former seems more standard.
  • 2
1 Solution
ext2Author Commented:
What I need is much like this:

LAML: Lisp Abstracted Markup Language
ext2Author Commented:
[[Request for refund of points]]

I think I've figured this all out.  The essential idea was to just use &rest (and not use &key) as such:

  (defun foo (&rest lst)
    (list "foo" (atts lst) (elements lst))

and then write one's own code to extract the attributes and elements from lst:

;; extract attributes from list
(defun atts (lst)
    ((null  (first  lst)) '())  ;; done
    ((listp (first  lst)) (atts (rest lst)))  ;; found element (ignore)
    ((null  (second lst)) nil) ;; error
    ((and (atom (first  lst))  ;; found attribute
          (atom (second lst)))
            (cons (list (first lst) (second lst))
                  (atts (rest (rest lst)))
    (t nil) ;; error

;; extract elements from list
(defun elements (lst)
    ((null  (first lst)) '()) ;; done
    ((listp (first lst)) (cons (first lst) (elements (rest lst)))) ;; found element
    (t (elements (rest (rest lst)))) ;; found attribute or error (ignore)

One can follow the same design as in LAML of generating the abstract syntax tree (AST) and then serializing it as XML.
Because you have presented a solution to your own problem which may be helpful to future searches, this question is now PAQed and your points have been refunded.


Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now