XML literals - vilinski/nemerle GitHub Wiki

Introduction

Nemerle has support for XML literals. Nemerle.Xml works on top of System.Xml.Linq. The macro creates XElement tree.

Features

1. Global namespace using DefineXmlns assembly attribute:

[assembly: DefineXmlns(ns1="some-ns")]

2. Local namespace using xmlns attribute:

xml <# <ns2:a ns2:aa="zz" xmlns:ns2="namespace-2"></ns2:a> #>;

3. Splice expressions:

  • Tag names (Only XName expressions).
  • Attributes. Only XAttribute expressions (for $-expressions) or IEnumerable[XAttribute] (for ..$-expressions).
  • Attribute values (Any types except XAttribute). When value is null either for reference or for nullable types, the whole attribute is removed (VB behaviour).
  • Tags. Only XElement expressions (for $-expressions) or IEnumerable[XElement] (for ..$-expressions). When value is null, nothing inserted in XML (XLinq behaviour).
  • Text (Any type which can be converted to string with XLinq). When value is null, nothing is inserted in XML (XLinq behaviour).
4. Control flow expressions:
  • foreach. Iterates over tag for each list entry:
  <li $foreach (p in props)>$(p.Name) : $(p.PropertyType)</li> 

The standard foreach macro is used. Most of its features are supported (pattern matching should work too)

  • when. Produces tag when the condition is true:
  <H2 $when (props.Length > 0)>Properties</H2> 
  • unless. Produces tag when the condition is false:
  <H2 $unless (props.IsEmpty())>Events</H2> 

5. XML correctness control (without schema) is done in compile time. 6. The XML tags can be closed without specifying name: > (Like in VB).

Example

using Nemerle.Collections;
using Nemerle.Xml;

using System;
using System.Console;
using System.Xml.Linq;

[assembly: DefineXmlns(ns1="some-ns")]

class TestClass
{
  public Prop1 : int { get; set; }
  public Prop2 : string { get; set; }
}

module Program
{
  Main() : void
  {
    def makeClassInfoPage(cls : Type) : void
    {
      def props = cls.GetProperties();
      def events = cls.GetEvents();
      def title = $"The class <$(cls.Name)>";
      def html = xml <# 
        <html>
          <head>
            <title>$title</title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 
            <link rel="stylesheet" href="http://rsdn.ru/css/article.css" type="text/css" />
          </head>
          <body marginwidth="20" marginheight="20">
            <H1>$title</H1>

            <H2 $unless (props.IsEmpty())>Properties</H2>
            <ol $unless (props.IsEmpty())>
              <li $foreach (p in props)>$(p.Name) : $(p.PropertyType)</li>
            </ol>

            <H2 $unless (events.IsEmpty())>Events</H2>
            <ol $unless (events.IsEmpty())>
              <li $foreach (e in events)>$(e.Name) : $(e.EventHandlerType)</li>
            </ol>
          </body>
        </html>
   #>;

      def path = IO.Path.ChangeExtension(IO.Path.GetTempFileName(), "html");
      IO.File.WriteAllText(path, html.ToString());
      _ = Diagnostics.Process.Start(path);
    }

    makeClassInfoPage(typeof(XAttribute));
    makeClassInfoPage(typeof(TestClass));
  
    def z : int? = 42;
    def a = [XAttribute("LANG", "enu"), XAttribute("xx", "yy")];
    def e1 = xml <# <x /> #>;
    def elems = [XElement("w"), e1];
    def res1 = xml <# <e a="a" ns1:a=$z ..$a>Text $e1<ns2:a ns2:aa="zz" xmlns:ns2="namespace-2"></ns2:a> abc ..$elems</e> #>;
    WriteLine(res1);
    def name = XName.Get("dyn"); 
    def res2 = xml <# <ns2:a xmlns:ns2="namespace-2"><$name $when (z.HasValue) ns1:a="123"/></> #>;
    WriteLine(res2);
  }
}
⚠️ **GitHub.com Fallback** ⚠️