.NET 框架中的 XML:在 .NET 框架中使用 XML 架构执行代码生成[3]

[入库:2005年8月18日] [更新:2007年3月25日]

本文简介:选择自 dlt3e 的 blog

  
  • 向 xsd 根 元素添加可被我的处理器理解的特性(可能添加很多),以便应用自定义,这种方法类似于类型化数据集方法。 单击此处可获得更多相关信息。
  
  • 通过架构注释使用内置的 xsd 可扩展性,以便任意进行自定义。它只需向某种代码生成管线中添加类型,即可在基本生成发生后执行。
  
  
  第一种方法最初可能很有吸引力,因为它非常简单。我只需添加一个特性,然后相应地修改处理器以检查该特性:
  
  架构:
  
  <xs:schema elementformdefault="qualified" xmlns:xsd="http://www.w3.org/2001/xmlschema" xmlns:code="http://weblogs.asp.net/cazzu" code:fieldstoproperties="true">
  
  代码:
  
  xmlschema xsd;
  // load the xmlschema.
  ...
  foreach (xmlattribute attr in xsd.unhandledattributes)
  {
   if (attr.namespaceuri == "http://weblogs.asp.net/cazzu")
   {
   switch (attr.localname)
   {
   case "fieldstoproperties":
   if (bool.parse(attr.value)) convertfieldstoproperties(ns);
   break;
   ...
   }
   }
  }
  
  这正是您通常会在其他从 xsd 到类的生成器中看到的方法(您可以在 code generation network 中找到大量类似的生成器)。遗憾的是,该方法将导致长长的 switch 语句、无尽的特性,并最终导致代码难以维护并缺乏可扩展性。
  
  第二种方法更为健壮,因为它从一开始就考虑了可扩展性。xsd 通过 元素提供此类扩展工具,该元素可以是架构中几乎所有项目的子元素。我将利用该元素及其 子元素,以便使开发人员可以指定运行哪些(任意)扩展以及按什么顺序运行。这样的扩展架构将如下所示:
  
  <xs:schema elementformdefault="qualified" xmlns:xs="http://www.w3.org/2001/xmlschema"> <xs:annotation> <xs:appinfo> <code xmlns="http://weblogs.asp.net/cazzu"> <extension type="xsdgenerator.extensions.fieldstopropertiesextension, xsdgenerator.customtool" /> </code> </xs:appinfo> </xs:annotation>
  
  当然,每个扩展都将需要实现一个公共接口,以便自定义工具可以轻松地执行各个扩展:
  
  public interface icodeextension { void process( system.codedom.codenamespace code, system.xml.schema.xmlschema schema ); }
  
  通过预先提供此类可扩展性,当产生新的自定义需要时,就可以很容易地进行其他自定义。甚至还可以从一开始就将最基本的代码实现为扩展。
  
  可扩展的代码生成工具
  我将修改 processor 类以添加这种新功能,并且将简单地从架构中检索各个 元素。尽管如此,这里还需要提出一个警告:与那些为元素、特性、类型等公开的 post schema compilation infoset 属性不同,在架构级别没有针对注释的类型化属性。也就是说,没有 xmlschema.annotations 属性。因此,需要对 xmlschema.items 的一般性预编译属性进行迭代,以便查找注释。而且,在检测到 xmlschemaannotation 项目之后,再次需要对其自己的 items 一般性集合进行迭代,这是因为除了 子元素以外,还可能有 子元素,而它也缺少类型化属性。当最终通过 xmlschemaappinfo.markup 属性获得 appinfo 的内容之后,我们所得到的全部内容是一个 xmlnode 对象数组。您可以想像如何进行后续处理:对节点进行迭代,再对其子元素进行迭代,等等。这将产生非常丑陋的代码。
  
  值得庆幸的是,xsd 文件只是一个 xml 文件,因此可以使用 xpath 来对其进行查询。
  
  为了提高执行速度,我将在 processor 类中保留 xpath 的静态编译表达式,它将在其静态构造函数中进行初始化:
  
  public sealed class processor
  {
   public const string extensionnamespace = "http://weblogs.asp.net/cazzu";
   private static xpathexpression extensions;
   static processor()
   {
   xpathnavigator nav = new xmldocument().createnavigator();
   // select all extension types.
   extensions = nav.compile
   ("/xs:schema/xs:annotation/xs:appinfo/kzu:code/kzu:extension/@type");
   // create and set namespace resolution context.
   xmlnamespacemanager nsmgr = new xmlnamespacemanager(nav.nametable);
   nsmgr.addnamespace("xs", xmlschema.namespace);
   nsmgr.addnamespace("kzu", extensionnamespace);
   extensions.setcontext(nsmgr);
   }
  
  注 有关 xpath 预编译和执行的优点、细节和高级应用的更多信息,请参阅 performant xml (i): dynamic xpath expressions compilation 和 performant xml (ii): xpath execution tips。
  
  process() 方法需要在将 codenamespace 返回给调用方之前,执行该查询并执行它找到的每个 icodeextension 类型:
  
  xpathnavigator nav;
  using ( filestream fs = new filestream( xsdfile, filemode.open ) )
  { nav = new xpathdocument( fs ).createnavigator(); }
  xpathnodeiterator it = nav.select( extensions );
  while ( it.movenext() )
  {
   type t = type.gettype( it.current.value, true );
   // is the type an icodeextension?
   type iface = t.getinterface( typeof( icodeextension ).name );
   if (iface == null)
   throw new argumentexception( "invalid extension type '" +
   it.current.value + "'." );
   icodeextension ext = ( icodeextension ) activator.createinstance( t );
   // run it!
   ext.process( ns, xsd );
  }
  return ns;
  

本文关键:.NET 框架中的 XML:在 .NET 框架中使用 XML 架构执行代码生成
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top