VB XML 料理ブック レシピ 1 : XML リテラルを使用した XML 変換 (Doug Rothaus)

Visual Basic XML リテラルを使用した XSLT 変換の置き換えに関するブログを書いていたのですが、あまりにも長くなってしまいました。そこで Avner Aharoni と話し合って、いくつかのエントリに分割してシリーズ物にすることにしました。数か月前に始まった LINQ 料理ブックの例にならったのです。

ここで VB XML 料理ブックについてご紹介します。このシリーズでは、Visual Basic で XML リテラルを使用する、簡単で速いソリューションをお見せします。多くの場合、直接置き換えられる機能があるか、または非常に近い機能があるときには、XSLT と XPath を参照します。Visual Basic 2008 から使用できるようになった XML リテラル、XML 軸プロパティ、および LINQ to XML を使うと XML を簡単に使用したり変換したりできます。

この初回のブログでは、XML リテラルと LINQ を使用して単純な XML 変換を行う方法をお見せします。ここに示す例では、LINQ クエリまたは他のソース (XML リテラルのコレクションを返すプロパティや関数など) から XML リテラルのコレクションを返す埋め込み式を使用します。XSLT 変換全体を数行の Visual Basic コードで置き換える方法をお見せします。

最初の例を見てみましょう。このブログに添付されている XML ファイルには、XML ドキュメント (AWContacts.xml) の SQL Server 用 AdventureWorks サンプル データベースの Contacts の一部が含まれています。各 <Contact> 要素に <EmailAddress> サブ要素があります。次のコードでは、ソース ドキュメントにある電子メール アドレスだけを使用して新しい XML ドキュメントを作成します。

Imports <xmlns="https://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 を使用して "テンプレート" 関数を作成し、XML リテラルを使用して、新しい XML ドキュメントを作成し、XML を読み込んで保存します。XML 子軸プロパティは、<EmailAddress> サブ要素のコレクションを参照します。<xsl:copy-of> 要素の代わりに埋め込み式を使用して、要素のコレクションを新しいドキュメントに追加します。ついに、XSLT や XPath を使わずにドキュメントを変換しました。同じ例で XSLT (および Visual Basic コード) を使った場合はどのようになるか、見てみましょう。

Recipe1.xslt

<?xml version='1.0'?>

<xsl:stylesheet

  version="1.0"

  xmlns:xsl="https://www.w3.org/1999/XSL/Transform"

  xmlns:aw="https://SampleSchema/AWContacts"

  xmlns:aci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo"

  xmlns:crm="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactRecord"

  xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="aw:Contacts">

    <EmailAddresses>

      <xsl:copy-of select="aw:Contact/aw:EmailAddress"/>

    </EmailAddresses>

  </xsl:template>

</xsl:stylesheet>

Recipe1_XSLT Visual Basic コード

 

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 バージョンではコードの量が 2 倍になり、正直に言って、作成するのに VB バージョンより時間がかかってしまいました。Visual Basic での XML 名前空間のサポートは XSLT (1.0) よりシンプルで、XML 名前空間が確認できない XML 要素の既定の XML 名前空間を定義できました。

もう 1 つ重要なことは、Visual Basic の XML リテラルで提供される IntelliSense のサポートによって、生産性が向上する点です。このブログに添付されているスキーマ ファイルを追加し、スキーマの名前空間をインポートすることで、XML の子要素と子孫要素、および属性の、入力候補の一覧を得ることができました。詳細については、「Visual Basic における XML Intellisense」を参照してください。

LINQ の使用

さらに、LINQ を使用して、変換にクエリ機能を追加することができます。XSLT では、<xsl:for-each> 要素を使用して結果をループし、<xsl:if> 要素を使用して特定の条件をテストします。LINQ を使用する場合は、これらの処理を簡単に行うことができます。

たとえば、ソース ドキュメントの各 <Contact> 要素には <EmailPromotion> サブ要素があります。このサブ要素は、その Contact が会社からのプロモーションの電子メールの受信を望んでいるかどうかを識別します。次のコードでは同じドキュメントが作成されますが、そのドキュメントには、プロモーションの電子メールの受信を望む Contacts の電子メール アドレスだけが含まれます。

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

                  <EmailPromotionList>

                      <%= From contact In xmlDoc.<Contacts>.<Contact> _

                          Where contact.<EmailPromotion>.Value > 0 _

                          Select contact.<EmailAddress> %>

                  </EmailPromotionList>

対応する XSLT コードは次のようになります。

  <xsl:template match="aw:Contacts">

    <EmailAddresses>

      <xsl:for-each select="aw:Contact">

        <xsl:if test="aw:EmailPromotion &gt; 0">

          <xsl:copy-of select="aw:EmailAddress"/>

        </xsl:if>

      </xsl:for-each>

    </EmailAddresses>

  </xsl:template>

最後の例ではさらに進んで、ソース XML ドキュメントの内容を新しいフォーマットに変換します。これを行うには、LINQ クエリで XML リテラルのコレクションを返すようにします。埋め込み式を使用して、ソース ドキュメントの値を新しい XML リテラルの要素や属性にコピーできます。この例では、変換後のドキュメントで <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:template match="aw:Contacts">

    <EmailPromotionList>

      <xsl:for-each select="aw:Contact">

        <xsl:if test="aw:EmailPromotion &gt; 0">

          <Email>

            <xsl:attribute name="promotion">

              <xsl:value-of select="aw:EmailPromotion"/>

            </xsl:attribute>

            <xsl:value-of select="aw:EmailAddress"/>

          </Email>

        </xsl:if>

      </xsl:for-each>

    </EmailPromotionList>

  </xsl:template>

今回は、<xsl:copy-of>、<xsl:for-each>、<xsl:template>、<xsl:if>、<xsl:value-of>、および <xsl:attribute> の各要素の代わりに Visual Basic、XML リテラル、および LINQ を使用し、XPath の代わりに XML 軸プロパティを使用して、XML 変換用の、単純でありながら非常に便利なツールを作成する方法をお見せしました。

続編をお楽しみに。

VB チーム

投稿 : 2008 年 2 月 21 日 12:22 PM

分類 : LINQ/VB9OrcasVB2008Doug RothausXMLVB XML Cookbook

添付ファイル : AdventureWorksContacts.zip

VB チームの Web ログhttps://blogs.msdn.com/vbteam/archive/2008/02/21/vb-xml-cookbook-recipe-1-xml-transformations-using-xml-literals-replacing-xsl-for-each-doug-rothaus.aspx (英語) より