`
knat
  • 浏览: 482 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Metah.X: An XML Metaprogramming Language

阅读更多
Metah.X(简称MX)用自创的语法实现了XML Schema 1.0的语义,并且用C#实现了一个Schema-lized Document Object Model (SDOM),编译器编译MX代码后将生成使用SDOM的C#代码,这将XML Schema的语义映射到C#上,从而完全释放出XML Schema的力量。尽管现在只有C#版,实现Java版或其它语言版本是完全可能的。
MX是个开源项目,欢迎参与,比如实现Java版或其它语言版本;MX没有定型,欢迎提出修改意见。请访问:http://metah.codeplex.com/
XML Schema定义了XML数据(或叫XML实例)的形状及需要遵守的规则,比如下面的XSD代码:
<?xml version="1.0" encoding="utf-8"?>
<!--HelloWorld.xsd-->
<schema targetNamespace="http://schemas.example.com/projecta" elementFormDefault="qualified"
    xmlns:tns="http://schemas.example.com/projecta" xmlns="http://www.w3.org/2001/XMLSchema">
    <simpleType name="String20">
        <restriction base="string">
            <minLength value="1"></minLength>
            <maxLength value="20"></maxLength>
        </restriction>
    </simpleType>
    <simpleType name="PhoneCategory">
        <restriction base="string">
            <enumeration value="Unknown"></enumeration>
            <enumeration value="Work"></enumeration>
            <enumeration value="Home"></enumeration>
        </restriction>
    </simpleType>
    <complexType name="Phone">
        <simpleContent>
            <extension base="tns:String20">
                <attribute name="Category" use="optional" type="tns:PhoneCategory"></attribute>
            </extension>
        </simpleContent>
    </complexType>
    <complexType name="Customer">
        <sequence>
            <element name="Phone" minOccurs="1" maxOccurs="unbounded" type="tns:Phone"></element>
        </sequence>
        <attribute name="Name" use="required" type="tns:String20"></attribute>
        <attribute name="Email" use="required">
            <simpleType>
                <restriction base="tns:String20">
                    <pattern value="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}"></pattern>
                </restriction>
            </simpleType>
        </attribute>
        <attribute name="RegistrationDate" use="optional" type="dateTime"></attribute>
    </complexType>
    <element name="Customer" type="tns:Customer"></element>
</schema>

下面是合法的XML数据:
<e0:Customer Name="Tank" Email="tank@example.com" RegistrationDate="2014-04-15T16:56:53.0568964Z" xmlns:e0="http://schemas.example.com/projecta">
    <e0:Phone Category="Work">12345678-334</e0:Phone>
    <e0:Phone>87654321</e0:Phone>
</e0:Customer>

因为XSD相当繁琐不便于书写,MX自创了用户友好的语法来表达XML Schema的语义,下面的MX代码和上面的XSD代码表达了相同的语义:

//HelloWorld.mxcs
xnamespace {"http://schemas.example.com/projecta"} [namespace: Example.ProjectA] {
    type String20 restrict String
        facets {
            lengthrange: 1..20;
        };
    ;
    type PhoneCategory restrict String
        facets{
            enums: Unknown = "Unknown", Work = "Work", Home = "Home"
        };
    ;
    type Phone extend String20
        attributes {
            attribute Category[?] as PhoneCategory;
        };
    ;
    type Customer
        attributes {
            attribute Name as String20;
            attribute Email as
                type restrict String20
                    facets {
                        patterns: @"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}";
                    };
                ;
            ;
            attribute RegistrationDate[?] as DateTime;
        };
        children {
            element Phone[+; membername: Phones] as Phone;
        };
    ;
    element Customer as Customer;
}

MX编译器编译HelloWorld.mxcs后,将生成如下的C#代码:
//HelloWorld.mxcs.cs
//Generated by MX compiler
namespace Example.ProjectA
{
    public partial class PhoneCategory : ...
    {
        public static readonly string @Unknown = "Unknown";
        public static readonly string @Work = "Work";
        public static readonly string @Home = "Home";
        ...
    }
    public partial class Phone : ...
    {
        public partial class AttributeSetClass : ...
        {
            public string Category_Value { get; set; }
            ...
        }
        public AttributeSetClass AttributeSet { get; set; }
        public AttributeSetClass EnsureAttributeSet();
        public string Value { get; set; }
        ...
    }
    public partial class Customer : ...
    {
        public partial class AttributeSetClass : ...
        {
            public string Name_Value { get; set; }
            public string Email_Value { get; set; }
            public DateTime? RegistrationDate_Value { get; set; }
            ...
        }
        public AttributeSetClass AttributeSet { get; set; }
        public AttributeSetClass EnsureAttributeSet();
        public partial class ComplexChildClass : ...
        {
            public partial class Phones_Class : ...
            {
                public partial class ItemClass : ...
                {
                    public Phone Type { get; set; }
                    ...
                }
                public ItemClass CreateAndAddItem();
                ...
            }
            public Phones_Class Phones { get; set; }
            public Phones_Class Ensure_Phones();
            ...
        }
        public ComplexChildClass ComplexChild { get; set; }
        public ComplexChildClass EnsureComplexChild();
        ...
    }
    public partial class Customer_ElementClass : ...
    {
        public Customer Type { get; set; }
        public static bool TryLoadAndValidate(XmlReader reader, Metah.X.Context context, out Customer_ElementClass result);
        ...
    }
}

使用编译器生成的代码,就可以创建、查询、修改、保存、装载及验证XML数据,下面的手写代码演示了如何使用编译器生成的代码:
//Program.cs
using System;
using System.Xml;//for XmlReader & XmlWriter
using X = Metah.X;

namespace Example.ProjectA {
    class Program {
        static void Main(string[] args) {
            var customer = new Customer();
            var cattset = customer.EnsureAttributeSet();
            cattset.Name_Value = "Tank";
            cattset.Email_Value = "tank@example.com";
            cattset.RegistrationDate_Value = DateTime.Now;
            var phones = customer.EnsureComplexChild().Ensure_Phones();
            var phone = phones.CreateAndAddItem();
            phone.EnsureAttributeSet().Category_Value = PhoneCategory.Work;
            phone.Value = "12345678-334";
            phones.CreateAndAddItem().Value = "87654321";
            var customerElement = new Customer_ElementClass { Type = customer };
            using (var writer = XmlWriter.Create(@"d:\customer.xml", new XmlWriterSettings { Indent = true }))
                customerElement.Save(writer);
            //
            var ctx = new X.Context();
            using (var reader = XmlReader.Create(@"d:\customer.xml")) {
                Customer_ElementClass customerElement2;
                if (Customer_ElementClass.TryLoadAndValidate(reader, ctx, out customerElement2)) {
                    var customer2 = customerElement2.Type;
                    Console.WriteLine("Name={0}, Email={1}, RegistrationDate={2}",
                        customer2.AttributeSet.Name_Value, customer2.AttributeSet.Email_Value, customer2.AttributeSet.RegistrationDate_Value);
                    foreach (var phone2 in customer2.ComplexChild.Phones) {
                        Console.WriteLine("\tCategory={0}, Value={1}", phone2.Type.AttributeSet.Category_Value, phone2.Type.Value);
                    }
                    customer2.AttributeSet.Name_Value += "-Knat";
                    customer2.AttributeSet.RegistrationDate = null;
                    var phone3 = customer2.ComplexChild.Phones.CreateAndAddItem();
                    phone3.EnsureAttributeSet().Category_Value = PhoneCategory.Home;
                    phone3.Value = "11223344";
                    using (var writer = XmlWriter.Create(@"d:\customer2.xml", new XmlWriterSettings { Indent = true }))
                        customerElement2.Save(writer);
                }
                else {
                    foreach (var diag in ctx.Diagnostics)
                        Console.WriteLine(diag);
                }
            }
        }
    }
}

下面是d:\customer.xml的内容:
<?xml version="1.0" encoding="utf-8"?>
<e0:Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="e0:Customer" Name="Tank" Email="tank@example.com" RegistrationDate="2014-04-17T08:45:21.4460232Z" xmlns:e0="http://schemas.example.com/projecta">
  <e0:Phone xsi:type="e0:Phone" Category="Work">12345678-334</e0:Phone>
  <e0:Phone xsi:type="e0:Phone">87654321</e0:Phone>
</e0:Customer>

下面是d:\customer2.xml的内容:
<?xml version="1.0" encoding="utf-8"?>
<e0:Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="e0:Customer" Name="Tank-Knat" Email="tank@example.com" xmlns:e0="http://schemas.example.com/projecta">
  <e0:Phone xsi:type="e0:Phone" Category="Work">12345678-334</e0:Phone>
  <e0:Phone xsi:type="e0:Phone">87654321</e0:Phone>
  <e0:Phone xsi:type="e0:Phone" Category="Home">11223344</e0:Phone>
</e0:Customer>

也就是说,MX的用处 = XML Schema的用处 + Document Object Model的用处。欲知详情,请访问:http://metah.codeplex.com/
  • 大小: 24.7 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics