Oskar
Oskar

Reputation: 37

How to parse an XML to S-Expression for lisp using C#?

I want to be able to load any xml file and convert it into s-expression for lisp. Does anyone have an idea how this could be done using c#?

I have no prior experience in working either with lisp or s-expression and my main problem is that I can't figure out how to represent s-expression structure in code.

I'd appreciate any hint on that.

I was thinking of using linq to xml and maybe deserialize this xml to c# objects, and then serialize it to s-expression and but I'm not sure if that's the right way to do this.

e.g. That's what I load:

<document author="[email protected]">
<para>This is a paragraph <footnote>(just a little one)</footnote>.</para>
<para>Ha! I made you say "underwear".</para>
</document>

That's what I would like to receive:

(document author: "[email protected]"
  (para "This is a paragraph " (footnote "(better than the one under there)") ".")
  (para "Ha! I made you say \"underwear\"."))

Upvotes: 2

Views: 375

Answers (1)

Renat
Renat

Reputation: 9002

You may use visitor pattern over XmlReader to traverse the xml and generate S-Expression alongside. This example generates quite close output (replace Console with a StringBuilder object if output is required as a string):

   var t = @"<document author=""[email protected]"">
<para>This is a paragraph <footnote>(better than the one under there)</footnote>.</para>
<para>Ha! I made you say ""underwear"".</para>
</document>";

    var xmlTextReader = XmlTextReader.Create(new StringReader(t));

    Visit(xmlTextReader, (XmlNodeType nodeType, XmlReader element) =>
    {
        switch (nodeType)
        {
            case XmlNodeType.Element:
                Console.WriteLine();
                Console.Write(new string('\t', element.Depth));
                Console.Write("(" + element.Name);
                break;
            case XmlNodeType.Text:
                if(!string.IsNullOrEmpty(element.Value))
                {
                    Console.Write(@" """ + element.Value.Replace(@"""", @"\""") + @"""");
                }
                break;
            case XmlNodeType.EndElement:
                Console.Write(")");
                break;
            case XmlNodeType.Attribute:
                Console.Write(" " + element.Name + @": """ + element.Value.Replace(@"""",@"\""") + @"""");
                break;
        }
    });
...


public static void Visit(XmlReader xmlReader, Action<XmlNodeType, XmlReader> visitor)
{
    while (xmlReader.Read())
    {
        visitor(xmlReader.NodeType, xmlReader);

        if (xmlReader.NodeType == XmlNodeType.Element)
        {
            while (xmlReader.MoveToNextAttribute())
            {
                visitor(xmlReader.NodeType, xmlReader);
            }
        }
    }
}

Upvotes: 1

Related Questions