{"id":387,"date":"2011-12-13T12:32:00","date_gmt":"2011-12-13T17:32:00","guid":{"rendered":"http:\/\/irreal.org\/blog\/?p=387"},"modified":"2011-12-13T12:40:09","modified_gmt":"2011-12-13T17:40:09","slug":"converting-s-expressions-to-xml-in-emacs","status":"publish","type":"post","link":"https:\/\/irreal.org\/blog\/?p=387","title":{"rendered":"Converting S-Expressions To XML In Emacs"},"content":{"rendered":"\n<p>My <a href=\"http:\/\/irreal.org\/blog\/?p=384\">last<\/a> <a href=\"http:\/\/irreal.org\/blog\/?p=385\">two<\/a> posts mentioned the ease with which s-expressions can be converted to XML and vice versa. Out of curiosity, I decided to write an sexpr to XML function in Elisp. <\/p>\n<p> The implementation consists of two functions. The first, <code>sexpr-&gt;xml<\/code>, does the actual conversion, while the second, <code>convert-to-xml<\/code>, takes care of Emacs bookkeeping details and acts as a driver. For convenience, <code>convert-to-xml<\/code> takes an sexpr as its input but it would be easy to have it operate on a region or even a whole buffer. <\/p>\n<p> We&#8217;ll use the example sexpr from Yegge&#8217;s <a href=\"http:\/\/sites.google.com\/site\/steveyegge2\/the-emacs-problem\">The Emacs Problem<\/a> post. Note that, again for simplicity, I am dealing with only a single record but everything would work exactly the same if there were multiple records wrapped in a <code>'(log &hellip;)<\/code> sexpr. <\/p>\n<pre class=\"src src-lisp\">'(record\n  (date <span style=\"color: #8b2252;\">\"2005-02-21T18:57:39\"<\/span>)\n  (millis 1109041059800)\n  (sequence 1)\n  (logger nil)\n  (level 'SEVERE)\n  (class <span style=\"color: #8b2252;\">\"java.util.logging.LogManager$RootLogger\"<\/span>)\n  (method 'log)\n  (thread 10)\n  (message <span style=\"color: #8b2252;\">\"A very very bad thing has happened!\"<\/span>)\n  (exception\n    (message <span style=\"color: #8b2252;\">\"java.lang.Exception\"<\/span>)\n    (frame\n      (class <span style=\"color: #8b2252;\">\"logtest\"<\/span>)\n      (method 'main)\n      (line 30))))\n<\/pre>\n<p> The converter is very simple. <\/p>\n<pre class=\"src src-emacs-lisp\"><span class=\"linenr\">1:  <\/span>(<span style=\"color: #7f007f;\">defun<\/span> <span style=\"color: #0000ff;\">sexpr-&gt;xml<\/span> (sexpr)\n<span class=\"linenr\">2:  <\/span>  (<span style=\"color: #7f007f;\">let<\/span> ((tag (car sexpr)))\n<span class=\"linenr\">3:  <\/span>    (princ (format <span style=\"color: #8b2252;\">\"&lt;%s&gt;\"<\/span> tag))\n<span class=\"linenr\">4:  <\/span>    (<span style=\"color: #7f007f;\">dolist<\/span> (o (cdr sexpr))\n<span class=\"linenr\">5:  <\/span>      (<span style=\"color: #7f007f;\">if<\/span> (atom o)\n<span class=\"linenr\">6:  <\/span>          (princ (format <span style=\"color: #8b2252;\">\"%s \"<\/span> o))\n<span class=\"linenr\">7:  <\/span>        (sexpr-&gt;xml o)))\n<span class=\"linenr\">8:  <\/span>    (princ (format <span style=\"color: #8b2252;\">\"&lt;\/%s&gt;\"<\/span> tag))))\n<\/pre>\n<p> It&#8217;s passed an sexpr whose first symbol is the XML tag. That gets saved away in the <code>let<\/code> on line 2 and printed as the opening tag on line 3. The <code>dolist<\/code> loop in lines 4&ndash;7 looks at each of the other objects in the sexpr. If an object is not another sexpr, it is printed with a trailing space. If it is another sexpr, <code>sexpr-&gt;xml<\/code> is called recursively on line 7 to process it. When all the objects in the sexpr have been processed, the end tag is printed on line 8. <\/p>\n<p> The output of <code>sexpr-&gt;xml<\/code> is a single line of XML with no formatting at all. Also, any <code>nil<\/code>s will appear explicitly in the XML instead of the tag pair being empty and all the quoted symbols will be wrapped in <code>&lt;quote&gt;<\/code> &hellip; <code>&lt;\/quote&gt;<\/code> tags because the lisp reader turns <code>'symbol<\/code> into <code>(quote symbol)<\/code>. <\/p>\n<p> Now let&#8217;s look at the driver function: <\/p>\n<pre class=\"src src-emacs-lisp\"><span class=\"linenr\">1:  <\/span>(<span style=\"color: #7f007f;\">defun<\/span> <span style=\"color: #0000ff;\">convert-to-xml<\/span> (sexpr)\n<span class=\"linenr\">2:  <\/span>  (<span style=\"color: #7f007f;\">with-output-to-temp-buffer<\/span> <span style=\"color: #8b2252;\">\"*XML*\"<\/span>\n<span class=\"linenr\">3:  <\/span>    (sexpr-&gt;xml sexpr)\n<span class=\"linenr\">4:  <\/span>    (set-buffer <span style=\"color: #8b2252;\">\"*XML*\"<\/span>)\n<span class=\"linenr\">5:  <\/span>    (xml-mode)\n<span class=\"linenr\">6:  <\/span>    (replace-regexp <span style=\"color: #8b2252;\">\"\\\\bnil\\\\b<\/span><span style=\"color: #8b2252; font-weight: bold;\">\\\\<\/span><span style=\"color: #8b2252; font-weight: bold;\">|<\/span><span style=\"color: #8b2252;\">&lt;quote&gt;<\/span><span style=\"color: #8b2252; font-weight: bold;\">\\\\<\/span><span style=\"color: #8b2252; font-weight: bold;\">|<\/span><span style=\"color: #8b2252;\">&lt;\/quote&gt;\"<\/span> <span style=\"color: #8b2252;\">\"\"<\/span> nil (point-min) (point-max))\n<span class=\"linenr\">7:  <\/span>    (sgml-pretty-print (point-min) (point-max))))\n<\/pre>\n<p> Lines 2 and 3 call <code>sexpr-&gt;xml<\/code> and arrange for its output to go into a buffer named <code>*XML*<\/code>. When <code>sexpr-&gt;xml<\/code> returns, the <code>*XML*<\/code> buffer is selected and set to <code>xml-mode<\/code> (really <code>nxml-mode<\/code>). The <code>replace-regexp<\/code> on line 6 deletes any occurrences of <code>nil<\/code> and gets rid of <code>&lt;quote&gt;<\/code> and <code>&lt;\/quote&gt;<\/code> tags. Finally, <code>sgml-pretty-print<\/code> is called to format the XML nicely. <\/p>\n<p> That&#8217;s a lot of work for not very much code. We could, of course, take care of the formatting and fixing up the <code>nil<\/code> and <code>&lt;quote&gt;<\/code> problems right in <code>sexpr-&gt;xml<\/code> but I wanted to show how simple the conversion can be without a lot of busy details. Besides, we have the power of Emacs so it would foolish not to use it. <\/p>\n<p> The final result of running <code>convert-to-xml<\/code> on our sample sexpr is <\/p>\n<pre class=\"src src-xml\">&lt;<span style=\"color: #0000ff;\">record<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">date<\/span>&gt;2005-02-21T18:57:39\n  &lt;\/<span style=\"color: #0000ff;\">date<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">millis<\/span>&gt;1109041059800\n  &lt;\/<span style=\"color: #0000ff;\">millis<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">sequence<\/span>&gt;1\n  &lt;\/<span style=\"color: #0000ff;\">sequence<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">logger<\/span>&gt;\n  &lt;\/<span style=\"color: #0000ff;\">logger<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">level<\/span>&gt;SEVERE\n  &lt;\/<span style=\"color: #0000ff;\">level<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">class<\/span>&gt;java.util.logging.LogManager$RootLogger\n  &lt;\/<span style=\"color: #0000ff;\">class<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">method<\/span>&gt;log\n  &lt;\/<span style=\"color: #0000ff;\">method<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">thread<\/span>&gt;10\n  &lt;\/<span style=\"color: #0000ff;\">thread<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">message<\/span>&gt;A very very bad thing has happened!\n  &lt;\/<span style=\"color: #0000ff;\">message<\/span>&gt;\n  &lt;<span style=\"color: #0000ff;\">exception<\/span>&gt;\n    &lt;<span style=\"color: #0000ff;\">message<\/span>&gt;java.lang.Exception\n    &lt;\/<span style=\"color: #0000ff;\">message<\/span>&gt;\n    &lt;<span style=\"color: #0000ff;\">frame<\/span>&gt;\n      &lt;<span style=\"color: #0000ff;\">class<\/span>&gt;logtest\n      &lt;\/<span style=\"color: #0000ff;\">class<\/span>&gt;\n      &lt;<span style=\"color: #0000ff;\">method<\/span>&gt;main\n      &lt;\/<span style=\"color: #0000ff;\">method<\/span>&gt;\n      &lt;<span style=\"color: #0000ff;\">line<\/span>&gt;30\n      &lt;\/<span style=\"color: #0000ff;\">line<\/span>&gt;\n    &lt;\/<span style=\"color: #0000ff;\">frame<\/span>&gt;\n  &lt;\/<span style=\"color: #0000ff;\">exception<\/span>&gt;\n&lt;\/<span style=\"color: #0000ff;\">record<\/span>&gt;\n<\/pre>\n<p> Any Elisp coders out there might want to consider what a translator in the other direction (XML to s-expressions) would look like. Not having s-expressions to leverage makes the processing a little more difficult but not by much. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>My last two posts mentioned the ease with which s-expressions can be converted to XML and vice versa. Out of curiosity, I decided to write an sexpr to XML function in Elisp. The implementation consists of two functions. The first, &hellip; <a href=\"https:\/\/irreal.org\/blog\/?p=387\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[18,28],"class_list":["post-387","post","type-post","status-publish","format-standard","hentry","category-programming","tag-emacs","tag-emacs-lisp"],"_links":{"self":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/387","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=387"}],"version-history":[{"count":1,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/387\/revisions"}],"predecessor-version":[{"id":388,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/387\/revisions\/388"}],"wp:attachment":[{"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=387"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=387"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/irreal.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=387"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}