VB XML手册1:用XML常量进行XML转换

[原文作者]Doug Rothaus
 
     我正在做一个关于用Visual Basic XML Literals取代XSLT转换的博客,我发现这个博客将会很长,所以,Avner Aharoni 和我谈了之后决定像几个月前我们做的LINQ操作指南一样把它分为多个条目并成一个系列。
 
     先介绍一下VB XML的操作指南。这个操作指南介绍了如何在Visual Basic中使用XML Literals的快速而简单的方法。在很多情况下,我们将会参考有着直接或者是相近功能的XSLTXPath你将会发现用XML Literals来转换和翻译XML是一件快速而简单的事情,XML的轴属性,和LINQXML,这一切都是从Visual Basic 2008开始的。
 
    首先介绍如何用XML LiteralsLINQ执行简单的XML转换。每个例子都用了一个嵌入式表达,从LINQ队列或者其他的资源,比如属性或函数中返回一组XML Literals,只需几行Visual Basic代码就能完成整个XSLT的转换。
 
     先看第一个例子,我们用了一个包含SQL ServerXML文件(AWContacts.xml)。每一个<Contact>标签都有一个<EmailAddress>的子标签,下面的代码创建了一个新的在代码中含有e-mail地址的XML文件。

Imports <xmlns="http://SampleSchema/AWContacts">
 
Public Class XMLCookbook
 Private Sub Recipe1()
   Dim xmlDoc = XDocument.Load("AWContacts.xml")
 
   Dim emailDoc = <?xml version="1.0"?>
                   <EmailAddresses>
                       <%= xmlDoc.<Contacts>.<Contact>.<EmailAddress> %>
                  </EmailAddresses>
 
   emailDoc.Save("EmailAddresses.xml")
 End Sub
End Class

 

     如果用XSLT进行转换,我们将要花费更多。在这里,你只是用了一个Visual Basic创建一个template函数,然后用XML Literals加载并保存XML,就像创建一个新的XML文件一样。XML Child Axisproperty引用了一组<EmailAddress>子标签,你也可以用embedded expressionXML文件中增加标签而不是<xsl:copy-of>,这样你就不用XSLTXpath转换这个文件。接下来我们看一个XSLTVisual Basic代码)转换的例子。

Recipe1.xslt
<?xmlversion=1.0?>
<xsl:stylesheet
 version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:aw="http://SampleSchema/AWContacts"
 xmlns:aci="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo"
 xmlns:crm="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactRecord"
 xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
 <xsl:outputmethod="xml"indent="yes"/>
 <xsl:templatematch="aw:Contacts">
    <EmailAddresses>
      <xsl:copy-ofselect="aw:Contact/aw:EmailAddress"/>
    </EmailAddresses>
 </xsl:template>
</xsl:stylesheet>
Recipe1_XSLT Visual Basic Code
 
Public Class XMLCookbook
    Sub Recipe1_XSLT()
        Dim xslTransform As New System.Xml.Xsl.XslCompiledTransform
        xslTransform.Load("recipe1.xslt")
 
        Dim reader = Xml.XmlReader.Create("AWContacts.xml")
        Dim sw As New System.IO.StreamWriter("Recipe1.xml")
        Dim writer = Xml.XmlWriter.Create(sw)
 
        xslTransform.Transform(reader, writer)
        sw.Close()
    End Sub
End Class

 

     这里的XSLT转换出两端大量的代码,让我们花费了大量的工作创建VB版本。在Visual BasicXML命名空间比XSLT1.0)简单,我可以为XML元素定义一个缺省的XML命名空间而不需要特别的去定义一个XML命名空间。
     还有重要的一点,在Visual Basic能为XML Literals提供只能的支持,通过增加在博客附件中的schema文件然后继承这些schemas,我得到一个完整的XML子元素的列表,欲了解更多的信息,请参考XML Intellisense in Visual Basic.
 
     使用LINQ
 
     然后,你可以用LINQ在转换中增加一些查询功能。在XSLT中,你可以很轻易的用 <xsl:for-each>循环和 <xsl:if>判断来完成这个功能
 
     例如,在源文件中,每一个<Contact>标签都有一个<EmailPromotion>的子标签,这个标签确定了是否希望从该公司接收e-mail。下面的代码给出了一个例子,但是只包含了接受e-mail许可的e-mail地址。
 Dim promoList = <?xml version="1.0"?>

                  <EmailPromotionList>
                      <%= From contact In xmlDoc.<Contacts>.<Contact> _
                          Where contact.<EmailPromotion>.Value > 0 _
                          Select contact.<EmailAddress> %>
                  </EmailPromotionList>

     下面是相比较的XSLT代码:

 <xsl:templatematch="aw:Contacts">

    <EmailAddresses>
      <xsl:for-eachselect="aw:Contact">
        <xsl:iftest="aw:EmailPromotion &gt; 0">
          <xsl:copy-ofselect="aw:EmailAddress"/>
        </xsl:if>
      </xsl:for-each>
    </EmailAddresses>
 </xsl:template>

      上一个例子中,我们进一步的把源XML文件转化成一种新的格式。也可以用一个LINQ查询返回一组XMLLiterals。用嵌入式表达复制源文件中的值到新的XML Literal的元素或属性中。例如,新的文件将把<EmailAddress>替换为<Email>,原本<EmailPromotion>包含的信息转换为<Email>中的属性。

 
 Dim transformList = <?xml version="1.0"?>

                      <EmailPromotionList>
                          <%= From contact In xmlDoc.<Contacts>.<Contact> _
                              Where contact.<EmailPromotion>.Value > 0 _
                              Select <Email
                                       promotion=<%= contact.<EmailPromotion>.Value %>>
                                       <%= contact.<EmailAddress>.Value %>
                                     </Email> %>
                      </EmailPromotionList>

     下面是相比较的XSLT代码:

 <xsl:templatematch="aw:Contacts">

    <EmailPromotionList>
      <xsl:for-eachselect="aw:Contact">
        <xsl:iftest="aw:EmailPromotion &gt; 0">
          <Email>
            <xsl:attributename="promotion">
              <xsl:value-ofselect="aw:EmailPromotion"/>
            </xsl:attribute>
            <xsl:value-ofselect="aw:EmailAddress"/>
          </Email>
        </xsl:if>
      </xsl:for-each>
    </EmailPromotionList>
 </xsl:template>

      总之,我们看到如何使用Visual Basic, XML LiteralsLINQ来代替<xsl:copy-of>, <xsl:for-each>, <xsl:template>, <xsl:if>, <xsl:value-of> <xsl:attribute>标签,并用XML轴属性代替Xpath创造一个强大又简单的XML转换工具。

请看更多。。。。

Visual Basic 2008 隐藏彩蛋

[原文作者]:

[原文链接]:Hidden Gems in Visual Basic 2008

    昨天,我答应写一篇关于 Visual Basic  Visual Studio 2008里隐藏彩蛋的文章,这些彩蛋是你们在博客帖子或会议上从未见过的。我曾提及到了一些我最喜爱的特性,在BataⅠ版本的阐述中我尽情炫耀了智能感知(intellisence)的改进,尤其是对关键字、本地变量和表达式,自动完成语句的改进。在那篇文章中,我也提到一种语法新特性非严格委托(Relaxed Delegates),它允许你为事件(event)提供一个可替代的签名(alternate signatures)。这些都是很棒的特性但我要告诉你一些玩意!
    经过队员们的民意调查,最终我们挑选出了10个最重要的特性,我以前的文章里没有提及过的。我这里只是简单介绍,有兴趣的朋友可以继续研究。首先 ,我必须从基调特性(keynote feature)开始讲……
 
0)    多个 target Framework 支持(Multi-targetting

    简单的说,Multi-targetting支持你在VS2008VB9下用.NET 2.0 framework 进行编译。下面我将要讲到的所有特性都在.NET 2.0下有效,所以当你打开Visual Studio 创建一个project以后,把framework target设置为2.0(除了第5和第7项,因为它们需要LINQObjectsXML APILINQ是在.NET 3.5才推出)。

1)    输入推断(Type Inference
    Visual Basic 9里面,下面的这一小段代码以及Nothing都是延迟绑定(late-bound——在编译时(compile tine)一切都是延迟绑定,这就意味着你可以得到智能感知和输入推断。 
Dim dialog = New OpenFileDialog()       
Dim result = dialog.ShowDialog()       
Dim printStr = "C\"       
If result = Windows.Forms.DialogResult.OK Then           
printStr = dialog.FileName       
End If       
MsgBoxprintStr 
    这使得在输入代码时更加快捷,简单和准确。 这个特性和控制它的机制你可以在我们QA team里的Bill Horst写的文章里得到详尽描述。
2)    IF操作符
    还记得吗,IIF函数能返回一个对象(Object),这意味着你不需要通过智能感知或类型推断就可以得到默认的返回值(Object类型)。如果你坚持要类型安全或代码前绑定,可以强制转换,代码如下: 
 Dim intC As Integer = CIntIIfintA = intB intA intB – 1)) 
    现在用IF操作符,你可以这么写: 
Dim intD As Integer = IfintA = intB intA intB 
     如果加上类型推断,代码就更简单了: 
 

    我本人是能提高易读性的特性的坚定拥护者。
3)    对象初始化(Object Initializers
     总的来说,在.net framework里,对象初始化是一种类似于把Dimstatement combined整合在一起的表达式。这样使得参数构造器多少让人容易接受一些: 
Dim strm As New StreamWriter _                 
New FileStream"C\out.txt"FileMode.OpenOrCreate _                        
With {.Position = 10} 
    对象初始化使得创建一个数组对象更加容易: 
Dim Capitals() As City = {New City With {.Name = "Antanarivo" .Country = "Madagascar"} _
New City With {.Name = "Belmopan" .Country = "Belize"} _
New City With {.Name = "Monaco" .Country = "Monaco"} _New City With {.Country = "Palau" .Name = "Koror"}}
4)    允许空值(Nullable
    Nullable 是一种特性,可能你知道但没有关注过。它是一个基本的.NET 表达式,专门针对nullable 类型(整数,日期,等等)。在 LINQ  SQL 中使用 Visual Studio 2008中引入的对象相关映射层这个设计器,数据库中的可空行都被映射成为这种类型。其结果是你可以在VB中写出像下面这样的表达式,而得到正确的结果其中的空属性以null值传播。例如下面这点代码,在Country type中有个independence property nullable date 
Dim virginIslands As New Country With {.Independence = Nothing}       
Dim palau As New Country With {.Independence = #10/1/1994#}        
Dim vILength = #8/24/2005# – virginIslands.Independence ‘ Nothing       
Dim pLength = #8/24/2005# – palau.Independence ‘ 3980.000000
5)    LINQ to DataSet
     我爱死这个特性了,因为它意味着你可以不用调用其他数据访问技术就能收获LINQ的好处。我先填充了一个 DataSet,然后就可以对这个DataSet进行查询。 
Me.EmployeesTableAdapter.FillMe.NORTHWNDDataSet.Employees       
Dim query = From emp In Me.NORTHWNDDataSet.Employees _                   
Where emp.Country = "USA" _                   
Order By emp.HireDate _                   
Select emp       
Me.EmployeesBindingSource.DataSource = query 
6)    语法提示(Syntax Tooltips 
 
     

    再看看这个 

    还有这个

 

7)    XMLnamespace支持智能感知
    之前我们已经在博客上讲到过XML Intelligence,但是我们忽视了一点。
namespace被用在XML 文档中时,智能感知会对namespace前缀和local name进行匹配,你只要为输入带来很大便捷,你只要输入开头几个字母然后回车,VS会帮你找到匹配的字段并加上相应的前后缀。下面是个小例子,以一个输入文件开始,然后使用智能感知。
 

    此时我们只输入字母tVS会自动选中tomato 
 
 

8)    转到类型定义(GoTo Type Definition
    通常,当你定义了一个变量,你想通过Object Browser浏览它在代码中的类型定义的时候,现在你多了一种选择,通过context menu可以让你直接找到它的定义。这点非常好,尤其是涉及到类型推断时能帮你确定该变量的类型是否和你想象的一致。 
 
 

9)  循环变量的输入推断(Type inference for loop variables
    检查下面这段代码: 
 
    还有这段:
 
 

     如果没有指定控制变量的类型,它会根据表达式或循环的信息从右往左推断。

10)    性能的提高以及非封闭性操作 
    后台编译器有一个非常强大的特性,它可以给你及时地反馈只要你写的代码正确。在这个版本的Visual Studio中我们对后台编译器做了很大的改进,我们相信后台编译器比以前快3倍但只用原先1/3的内存。任何使用过VS2008 的人都会意识到这一点。虽然我们在性能上做了很大的改进,但是在大项目里面某些操作符仍然是一个巨大的花费,例如改变一个base classdeclaration 通常会被多次用到。如果在后台编译器工作之前,你试图调用一些依赖于编译信息的特性(例如IntellisenceDrop Downs),在以前版本的VS中会有一个长时间的停顿直到编译完成为止,但是现在这个问题解决了,当你想得到drop downs的时候就像这样: 
 
    集成开发环境照样能够响应用户操作。 

LINQ手册8:使用LINQ查询XML(Doug Rothaus)

配料:
·         Visual Studio 2008 (Beta2或更高版本)
类别:LINQ-ToXML
 
步骤:
·         使用VB 创建一个新的Console Application
·         创建RSS文档。添加以下代码到Sub Main中。
    Dim rss = <?xml version="1.0"?>
              <rss version="2.0">
                <channel>
                  <title>LINQ to XML in Visual Basic</title>
                  <description>Sample RSS Feed</description>
                  <language>en-us</language>
                  <pubDate>Tue, 18 Sep 2007 00:56:12 GMT</pubDate>
                  <item>
                    <title>Basic Instincts: Lambda Expressions</title>
                    <description>A new feature added to Visual Basic 9 to
                                 support Language Integrated Queries (LINQ),
                                 which adds data programmability to
                                 Visual Basic.</description>
                    <pubDate>Thu, 27 Sep 2007 23:54:55 GMT</pubDate>
                  </item>
                  <item>
                    <title>Visual Basic Pack for Visual Studio 2005 SDK</title>
                    <description>The Visual Basic Pack for the Visual Studio
                                 2005 SDK includes SDK samples converted into
                                 the Visual Basic language and a new wizard for
                                 generating Visual Basic-based integration
                                 packages for Visual Studio.</description>
                    <pubDate>Mon, 17 Sep 2007 23:58:49 GMT</pubDate>
                  </item>
                  <item>
                    <title>XML to Schema Tool</title>
                    <description>The XML to Schema tool is a free project item
                                 template to automate creation of XML schema
                                 sets from any number of XML documents. If you
                                 are working with Language Integrated Queries
                                 (LINQ) to XML in Visual Basic 9, this utility
                                 can significantly improve your editing
                                 experience by adding XML schemas (.xsd files)
                                 to your project that add IntelliSense for XML
                                 properties.</description>
                    <pubDate>Mon, 17 Sep 2007 23:59:43 GMT</pubDate>
                  </item>
                  <item>
                    <title>Line and Shape Controls in the Power Packs</title>
                    <description>Download the latest version of the Visual
                                 Basic 2005 Power Packs which now includes Line
                                 and Shape controls that enable you to draw
                                 lines, ovals, and rectangles on forms and
                                 containers at design time making it much easier
                                 to enhance the look of your user
                                 interface.</description>
                    <pubDate>Mon, 20 Aug 2007 20:24:25 GMT</pubDate>
                  </item>
                </channel>
              </rss>
 
   VB中你可以使用LINQ语法查询XML就像你在SQL Server或者其它数据库上查询数据和数据集合一样。不同之处在于你如何去查找XML 元素和属性。在VB中有些XML 的特性允许你使用类数据对象那样查找XML 的元素和属性。
   举例来说,要查找之前创建的XDocument对象中的<channel>元素,你只要编写一行简单的代码:rss.<rss>.<channel>.尽管这看起来只是查找出一个<channel>元素,但事实上代码返回的是<rss>对象中所有<channel>子元素的集合。这样你就能通过Index来查找特定的<channedl>元素,或者就像我们在标题中看的那样通过执行LINQ查询所有的元素集合。为了能查找XML元素的任意子元素,可以使用descendant语法"",示例rss.<rss>…<title>.为了查找属性,可以使用attribute语法"@,示例rss.<rss>.@version。这些为了在XDocumentXElement中查找元素和属性的语法被称之为XML Axis属性。
注意:在VBXML特性包含了XML智能感知,它可以在我们编码过程中使用XDocumentXElement这些LINQ to XML对象时提供它们的XML属性以及子元素列表。要启用XML智能感知只需将XML结构定义(XSD)文件添加到你的项目中。VB中的XML工具会在你没有XSD文件的前提下,通过XML文件的内容创建一个XSD文件。更多信息,请看XML IntelliSense in Visual Basic
   通过在VB中使用XML Axis属性,我们可以使用LINQ来查询XML内容。举例来说,以下的查询在RSS feed中执行了一次搜索,搜索的内容是<item><title><description>元素。添加代码到Sub Main中,并将其置于XDocument对象之后。
    Dim itemList1 = From item In rss.<rss>.<channel>.<item> _
                    Where item.<description>.Value.Contains("LINQ") Or _
                          item.<title>.Value.Contains("LINQ")
 
    Console.WriteLine("Items containing ‘LINQ’" & vbCrLf)
    For Each item In itemList1
      Console.WriteLine(vbTab & "Title: " & item.<title>.Value)
      Console.WriteLine(vbTab & "Description: " & item.<description>.Value)
      Console.WriteLine()
    Next
 
   注意示例代码的搜索是从XML元素的Value属性寻找匹配值。Value属性将从XML元素中返回的内容做为字符串。如果不这样处理的话,XML Axis属性将会对应元素名称的元素集合。但是当搜索XML属性时,你并不需要指定Value属性。这种情况下,XML Axis属性默认返回第一个匹配属性的Value.
   由于Value属性总是返回字符串,你或许需要将其转化成其它指定的类型来执行你的查询。举例来说,以       下代码示例搜索的是过去20天发布的RSS。添加代码到Sub Main末尾。
    Dim itemList2 = From item In rss.<rss>.<channel>.<item> _
                    Let pubDate = DateTime.Parse(item.<pubDate>.Value) _
                    Where pubDate >= _
                          DateTime.Now.Subtract(New TimeSpan(20, 0, 0, 0)) _
                    Select item
 
    Console.WriteLine("Items published in the last 20 days" & vbCrLf)
    For Each item In itemList2
      Console.WriteLine(vbTab & "Title: " & item.<title>.Value)
      Console.WriteLine(vbTab & "Publish Date: " & item.<pubDate>.Value)
      Console.WriteLine()
    Next
 
    按下F5查看代码运行情况。
 

让PInvoke简单

[原文作者]Jared Parsons
[原文链接]Making PInvoke Easy
 
     我非常兴奋的宣布我们最近发布了一个工具,这个工具对我们在托管代码中使用PInvoke非常有用。这个工具的名 字是PInvoke Interop Assistant”,“PInvoke Interop Assistant”作为PInvokeReverse PInvoke场景的一部分已经被包含在MSDN文章中。
 
    下面的链接是文章和工具
·         ToolCLRInsideOut2008_01.exe
 
 
   开发这个工具背后的动力是写PInvoke是一个艰难并且乏味的任务。有很多规则必须遵守,很多异常必须要考虑到。所有在简单的数据结构之外的东西必须专心的做,C当中微妙的语义会很大程度上改变所需的签名。不正确的翻译经常会导致不明确的异常或者崩溃。
 
   简而言之,这个差事没有什么乐趣。
 
   这个工具可以用很多方式让PInvoke产生更简单的进程。目标是为structunionsenumsconstantsfunctionstypedefs等等产生尽可能简单的托管代码。这些代码可以在VBC# 中生成。
 
   工具中三个选项卡的GUI版本:
1. Siglmp Search: 搜索常用的方法,然后翻译成托管代码。
2. Siglmp Translate Snippet:直接翻译C代码到托管的PInvoke签名中去。
3. SigExp:转换托管的二进制代码到C++ Reverse PInvoke 场景中。
 
   前面两个是我的工作部分,也是代表PInvoke的场景。第三个是Ladi Prosek写的,这部分另外一篇文章会讲到。我们选择SiglmpSigExp这两个名字来反映工具tblimp/tlbexp,因为他们有差不多的方法。
 
    直接翻译C代码到PInvoke签名中
 
    在PInvoke中大部分的冒险是,开发者想用托管代码中的一小部分C代码。典型的是一两个有C结构体的方法。以前,所有这样的情况需要从一开始就翻译进托管代码中。用这个工具,你只需要把代码粘贴到这个工具里面,然后它就会生成相应的签名。
 
    例如假设你想翻译下面的C代码到VB
 
struct S1
{
 int a;
 char[10] b;
};
 
float CalculateData(S1* p);
 
    把工具打开,转换到“Siglmp Translate Snippet”选项。粘贴这些代码,然后按Generate按钮。

    你也可以按“Auto Generate“,然后看着你键入的代码更新。
 
    这种翻译不限制于内置的 C类型。它还可以解决大多数通用的windows类型,例如HANDLEDWORD所有的这些到复杂的结构体例如WIN32_FIND_DATA
 
    搜索常用的方法
 
    通常开发者想在托管代码中用他们熟悉的C函数。这也是一个乏味的任务,因为如果这个签名现在还不是可以得到的,那么你就要从头编码。如果你不知道到哪个头文件里面去查的话,加一个常量是不易处理的。
    这个工具提供了一个有常用的方法,结构体,常量等的数据库。基本上windows.h包含了所有的东西。转换到Siglmp的搜索键,键入你想搜索的名字,然后敲generate。例如你想看WM_PAINT的值。   

     另外,工具的这部分还会做附属的分析。例如,选择一个有C结构的方法,它会自动生成方法的结构。例如,你选FindFirstFile,它会知道这个方法依赖于WIN32_FIND_DATA这个结构。另外,它还会注意到WIN32_FIND_DATA依赖于FILETIME然后会生成这两个到方法里面去。
 
<System.Runtime.InteropServices.StructLayoutAttribute( _
    System.Runtime.InteropServices.LayoutKind.Sequential, _
    CharSet:=System.Runtime.InteropServices.CharSet.[Unicode])> _
Public Structure WIN32_FIND_DATAW
    '''DWORD->unsigned int
    Public dwFileAttributes As UInteger
    '''FILETIME->_FILETIME
    Public ftCreationTime As FILETIME
    '''FILETIME->_FILETIME
    Public ftLastAccessTime As FILETIME
    '''FILETIME->_FILETIME
    Public ftLastWriteTime As FILETIME
    '''DWORD->unsigned int
    Public nFileSizeHigh As UInteger
    '''DWORD->unsigned int
    Public nFileSizeLow As UInteger
    '''DWORD->unsigned int
    Public dwReserved0 As UInteger
    '''DWORD->unsigned int
    Public dwReserved1 As UInteger
    '''WCHAR[260]
    <System.Runtime.InteropServices.MarshalAsAttribute( _
        System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=260)> _
    Public cFileName As String
    '''WCHAR[14]
    <System.Runtime.InteropServices.MarshalAsAttribute( _
        System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=14)> _
    Public cAlternateFileName As String
End Structure
 
<System.Runtime.InteropServices.StructLayoutAttribute( _
    System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure FILETIME
    '''DWORD->unsigned int
    Public dwLowDateTime As UInteger
    '''DWORD->unsigned int
    Public dwHighDateTime As UInteger
End Structure
 
Partial Public Class NativeMethods
    '''Return Type: HANDLE->void*
    '''lpFileName: LPCWSTR->WCHAR*
    '''lpFindFileData: LPWIN32_FIND_DATAW->_WIN32_FIND_DATAW*
    <System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint:="FindFirstFileW")> _
    Public Shared Function FindFirstFileW( _
        <System.Runtime.InteropServices.InAttribute(), _
            System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)> _
            ByVal lpFileName As String, _
        <System.Runtime.InteropServices.OutAttribute()> _
        ByRef lpFindFileData As WIN32_FIND_DATAW) As System.IntPtr
    End Function
End Class

 

    翻译大量的代码
 
   小的翻译器适合翻译小的代码段。如果你想要翻译大量的代码,像彼此依赖的头文件的话,小的翻译器就不会工作得很好了。你应该用这个工具的命令行的版本来翻译大量的代码。sigimp.exe。它是被设计用来进行很多头文件的翻译工作,然后产生大量的输出。
    结语
   以前这个工具就像是我项目的宠物。我十分的兴奋,现在客户可以利用它的优点,我也期待你们给我回馈。稍后,我会帖更多关于这个工具是怎么工作的文章。

VB XML 手册2:子代和父代

[原文作者]Doug Rothaus
 
 
   这个手册主要是讲,在XML文件中怎样使用Visual BasicXML轴属性和LINQ toXML对象访问子和父元素。
 
 
   Visual Basic提供XML轴属性,可以很容易的引用子节点和标记。这是使用XML经常会遇到的情况。你可能会需要引用下一级元素在XML的数据层次上的不同层级上出现。那样的话,你可以使用XML 子代轴属性
 
   XML子代轴属性是用三个跟随着你想引用的XML元素的周期来定义的。例如,在手册1中用到的AdventureWorks contacts source文件中(你可以从手册1下载这个XML文件和相关的模式)。里面有个<AdditonalContactInfo>元素,包括了关于联系方式例如电话号码,发货和帐单地址等等的信息。在<AdditionalContactInfo>元素里面的电话号码可以出现在这个元素值里面的任何位置。最终,你就可以用XML子代轴属性来引用电话号码这个元素。例如:
 
Dim xmlDoc = XDocument.Load("AWContacts.xml")
 
‘ Return all descendant <telephoneNumber> elements
Dim telephoneNumbers = _
 xmlDoc.<Contacts>.<Contact>.<aci:AdditionalContactInfo><act:telephoneNumber>
 
   XML子代轴属性返回XML数据层次中所有符合元素的集合。我们看一个更加完整的例子。下面的方法用XML子代轴属性返回一串联系名字和电话号码。
 
Imports <xmlns="http://SampleSchema/AWContacts">
Imports <xmlns:s="sample-output">
Imports <xmlns:aci="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo">
Imports <xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
 
Public Class Recipe2
 
 Public Function GetPhoneNumbers(ByVal xmlDoc As XDocument) As XElement
    Return <s:ContactPhoneNumbers>
             <%= From contact In xmlDoc.<Contacts>.<Contact> _
                 Where contact.<aci:AdditionalContactInfo><act:telephoneNumber>.<act:number>.Count > 0 _
                 Select <s:Contact>
                          <s:Name><%= contact.<FirstName>.Value & " " & _
                                      contact.<LastName>.Value %></s:Name>
                          <s:PhoneNumbers>
                            <%= From number In _
                                contact.<aci:AdditionalContactInfo><act:telephoneNumber>.<act:number> _
                                Select <s:Number><%= number.Value %></s:Number> _
                            %>
                          </s:PhoneNumbers>
                        </s:Contact> _
             %>
           </s:ContactPhoneNumbers>
 End Function
End Class
 
XSLT中,同样传输是这样的:
 
<?xmlversion=1.0?>
<xsl:stylesheet
 version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:aw="http://SampleSchema/AWContacts"
 xmlns:s="sample-output"
 xmlns:aci="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo"
 xmlns:crm="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactRecord"
 xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
<xsl:outputmethod="xml"indent="yes" />
 
 <xsl:templatematch="aw:Contacts">
    <s:ContactPhoneNumbers>
      <xsl:apply-templatesselect="aw:Contact" />
    </s:ContactPhoneNumbers>
 </xsl:template>
 
 <xsl:templatematch="aw:Contact">
    <xsl:iftest="count(aci:AdditionalContactInfo//act:telephoneNumber/act:number) > 0">
      <s:Contact>
        <s:Name>
          <xsl:value-ofselect="aw:FirstName"/>
          <xsl:text> </xsl:text>
          <xsl:value-ofselect="aw:LastName"/>
        </s:Name>
        <xsl:apply-templatesselect="aci:AdditionalContactInfo" />
      </s:Contact>
    </xsl:if>
 </xsl:template>
 
 <xsl:templatematch="aci:AdditionalContactInfo">
    <s:PhoneNumbers>
      <xsl:for-eachselect=".//act:telephoneNumber/act:number">
        <s:Number>
          <xsl:value-ofselect="."/>
        </s:Number>
      </xsl:for-each>
    </s:PhoneNumbers>
 </xsl:template>
 
</xsl:stylesheet>
 
   一个比较重要的需要注意的是,当子元素的位置总是一样的时候就不应该用XML子代轴属性。如果用XML 子轴属性去引用XML数据层次中的特定位置,你的代码会比使用XML子代轴属性去搜索整个XML数据层次中符合的项执行起来好很多。
 
父代
 
   XML轴属性使向下搜索XML数据层次快并且简单。然而,如果你想向上搜索XML数据层次呢?那样的话,你可以用XNode类的Ancestors方法。因为XML直接把LINQ to XML类的功能暴露出来,你可以用那些LINQ to XML类附带的功能。
 
   Ancestors()这个方法在XML数据层次中向上搜索那些符合给出元素名字的元素。传给Ancestors方法的元素的名字必须包括元素XML命名空间。可以用GetXmlNamespace operator返回基于给出的XMLprefix的命名空间。对于默认的XML命名空间,调用GetXmlNamespace操作不传入prefix。如果你在同样的XML命名空间中搜索一个已经引用的元素,可以用Name.Namespace属性访问已经引用的元素的命名空间。
 
   例如,下面的例子从AdventureWorks Contacts得到一串<telephoneNumber>元素(实际上,任何一个类型的phoneNumberType定义在ContactType.xsd文件里面),然后返回一串电话号码和跟电话号码相关的名字。这个例子调用Ancestors()方法去向上搜索XML数据层次中的<Contact>节点。
 
Imports <xmlns="http://SampleSchema/AWContacts">
Imports <xmlns:s="sample-output">
Imports <xmlns:aci="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo">
Imports <xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
 
Public Class Recipe2
 
 Public Function GetPhoneList(ByVal numberList As IEnumerable(Of XElement)) As XElement
    Return <s:PhoneNumberList>
             <%= From number In numberList _
                 Let contact = number.Ancestors(GetXmlNamespace() + "Contact") _
                 Select <s:PhoneNumber>
                          <s:Number type=<%= number.Name.LocalName %>>
                            <%= number.<act:number>.Value %>
                          </s:Number>
                          <s:Owner><%= contact.<FirstName>.Value & " " & _
                                       contact.<LastName>.Value %></s:Owner>
                      </s:PhoneNumber> _
             %>
           </s:PhoneNumberList>
 End Function
End Class
 
XSLT中,同样的传输是这样的:
 
<?xmlversion=1.0?>
<xsl:stylesheet
 version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:aw="http://SampleSchema/AWContacts"
 xmlns:s="sample-output"
 xmlns:aci="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo"
 xmlns:crm="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactRecord"
 xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
<xsl:outputmethod="xml"indent="yes" />
 
 <xsl:templatematch="aw:Contacts">
    <s:PhoneNumberList>
      <xsl:apply-templatesselect="aw:Contact//act:telephoneNumber" />
    </s:PhoneNumberList>
 </xsl:template>
 
 <xsl:templatematch="aw:Contact//act:telephoneNumber">
    <s:PhoneNumber>
      <s:Number>
        <xsl:attributename="type">
          <xsl:value-ofselect="name()" />
        </xsl:attribute>
        <xsl:value-ofselect="./act:number"/>
      </s:Number>
      <s:Owner>
        <xsl:value-ofselect="ancestor::aw:Contact/aw:FirstName"/>
        <xsl:text> </xsl:text>
        <xsl:value-ofselect="ancestor::aw:Contact/aw:LastName"/>
      </s:Owner>
    </s:PhoneNumber>
 </xsl:template>
</xsl:stylesheet>