3 ms·
You should try using a LISP like Racket for XML. Because XML can be expressed directly as S-expressions, XML and LISP go together like peanut butter and jelly.
by velcrovan 2y ago
You should try using a LISP like Racket for XML. Because XML can be expressed directly as S-expressions, XML and LISP go together like peanut butter and jelly.
<greeting attr="val" href="#">Hello <thing>world</thing><greeting>
(greeting ((attr "val") (href "#")) "Hello " (thing "world"))
- koito17 2y agoIn my experience, at least with Clojure, it's much more convenient to serialize XML into a map-like structure. With your example, the data structure would look like so. {:tag :greeting :attrs {:href "#" :attr "val"} :content ["Hello" {:tag :thing :content ["world"]}]} Some people use namespaced keywords (e.g. :xml/tag) to help disambiguate keys in the map. This kind of data structure tends to be more convenient than dealing with plain sexps or so-called "Hiccup syntax". i.e. [:greeting {:href "#" :attr "val"} "Hello" [:thing "world"]] The above syntax is convenient to write, but it's tedious to manipulate. For instance, one needs to dispatch on types to determine whether an element at some index is an attribute map or a child. By using the former data structure, one simply looks up the :attrs or :content key. Additionally, the map structure is easier to depth-first search; it's a one-liner with the tree-seq function. I've written a rudimentary EPUB parser in Clojure and found it easier to work with zippers than any other data structure to e.g. look for <rootfile> elements with a <container> ancestor. Zippers are available in most programming languages, thankfully, so this advantage is not really unique to Clojure (or another Lisp). However, I will agree that something like sexps (or Hiccup) is more convenient than e.g. JSX, since you are dealing with the native syntax of the language rather than introducing a compilation step and non-standard syntax.
- velcrovan 2y agoI have not looked into the use of zippers for this purpose, but I will do so! Racket has helper libraries like TxExpr (https://docs.racket-lang.org/txexpr/index.html https://docs.racket-lang.org/txexpr/index.html) that make it pretty easy to manipulate S-expressions of this kind.
- zoogeny 2y agoThis looks like it loses the distinction between attributes and nested tags? As in, I don't see a difference between `(attr "val")` which expresses an attribute key/value pair and `(thing "world")` which expresses a tag/content relationship. Even if I thought the rule might be "if the first element of the list is a list itself then it should be interpreted as a set of attribute key value pairs" then I would still be ambiguous with: (foo (bar "baz") "content") which could serialize to either: <foo bar="baz">content</foo> or: <foo><bar>baz</bar>content</foo> In fact, this ambiguity between attributes and children has always been one of the head scratching things for me about XML. Well, the thing I've always disliked the most is namespaces but that is another matter.
- shawn_w 2y agoThere's no ambiguity. The first element is a symbol that's the name of a tag. If the second element is a list of two element symbol + string lists, it's the attributes. If it's one of the other recognized types, it's part of the contents of the tag. See a grammar for the representation at https://docs.racket-lang.org/xml/index.html#%28def._%28%28lib._xml%2Fprivate%2Fxexpr-core..rkt%29._xexpr~3f%29%29 https://docs.racket-lang.org/xml/index.html#%28def._%28%28li... Most Scheme tools for working with XML use a different layout where a list starting with the symbol @ indicates attributes. See https://en.wikipedia.org/wiki/SXML https://en.wikipedia.org/wiki/SXML for it.
- zoogeny 2y agoI see, so my example should be: (foo (bar "baz") "content") vs (foo ((bar "baz")) "content") Where the first one would be the nested tags and the second one would be a single `bar="baz"` attribute. I would prefer the differentiation to be more explicit than the position and/or structure of the list, so the @ symbol modifier for the attribute list in other tools makes sense. The sibling comment with a map with a :attrs key feels even better. I don't work in languages with pattern matching or that kind of thing very often, but if I was wanting to know if a particular element had 1 or more attributes then being able to check a dictionary key just feels like a nicer kind of anchor point to match against.
- 2y ago
- froh 2y agoa lisp... like dsssl ? ;-)