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没有定型,欢迎提出修改意见。
XML Schema定义了XML数据(或叫XML实例)的形状及需要遵守的规则,比如下面的XSD代码:
<E1 xmlns="http://ns1"> <E2 A1="123">abc</E2> <E3 xmlns=""> <p:E4 xmlns:p="http://ns2" p:A1="true" A1="123" /> def </E3> </E1>
下面是合法的XML数据:
12345678-33487654321
因为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的内容:
下面是d:\customer2.xml的内容:
12345678-3348765432111223344
也就是说,MX的用处 = XML Schema的用处 + Document Object Model的用处。