VB XML 料理ブック レシピ 2 : 子孫と先祖 (Doug Rothaus)

料理ブックのこのレシピでは、XML ドキュメント内の子孫要素と先祖要素に Visual Basic、XML 軸プロパティ、および LINQ to XML オブジェクトを使用してアクセスする方法を紹介します。

子孫

Visual Basic には、子ノードと属性を簡単に参照できる XML 軸プロパティが用意されています。XML でよくあるように、XML 階層内の異なるレベルにあるサブ要素を参照したいことがあるでしょう。こうしたときに、XML 子孫軸プロパティを使用できます。

XML 子孫軸プロパティは、ピリオド 3 個の後に参照先の XML 要素を指定して示します。たとえば、レシピ 1 で使用した AdventureWorks の連絡先ソース ドキュメント (XML ドキュメントと関連スキーマは、レシピ 1 の記事からダウンロードできます) には、連絡先に関する電話番号や出荷先および請求先住所などの情報を格納する <AdditionalContactInfo> 要素があります。<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="https://SampleSchema/AWContacts">

Imports <xmlns:s="sample-output">

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

Imports <xmlns:act="https://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 では、同じものが次のように記述されます。

<?xml version='1.0'?>

<xsl:stylesheet

  version="1.0"

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

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

  xmlns:s="sample-output"

  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">

    <s:ContactPhoneNumbers>

      <xsl:apply-templates select="aw:Contact" />

    </s:ContactPhoneNumbers>

  </xsl:template>

 

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

    <xsl:if test="count(aci:AdditionalContactInfo//act:telephoneNumber/act:number) > 0">

      <s:Contact>

        <s:Name>

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

          <xsl:text> </xsl:text>

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

        </s:Name>

        <xsl:apply-templates select="aci:AdditionalContactInfo" />

      </s:Contact>

    </xsl:if>

  </xsl:template>

 

  <xsl:template match="aci:AdditionalContactInfo">

    <s:PhoneNumbers>

      <xsl:for-each select=".//act:telephoneNumber/act:number">

        <s:Number>

          <xsl:value-of select="."/>

        </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 階層の上のレベルにある、指定された要素名と一致する XML 要素を検索します。ただし、Ancestors メソッドに対して指定する要素名には、その要素の XML 名前空間も含める必要があります。指定する XML プレフィックスに基づいて XML 名前空間を返すには、GetXmlNamespace 演算子を使用できます。既定の XML 名前空間の場合、GetXmlNamespace 演算子を呼び出すだけでよく、プレフィックスを渡す必要はありません。既に参照先がわかっている要素と同じ XML 名前空間内で要素を検索する場合、参照される要素の XML 名前空間に Name.Namespace プロパティを使用してアクセスできます。

たとえば、次の例では、<telephoneNumber> 要素 (ContactTypes.xsd ファイル内で特定されるように、phoneNumberType 型のすべての要素) の一覧を AdventureWorks の連絡先サンプル ドキュメントから取得し、電話番号とそれに関連付けられた連絡先の名前の一覧を返します。サンプルでは、Ancestors() メソッドを呼び出し、XML 階層の上のレベルに向かって名前空間の <Contact> ノードを検索します。

Imports <xmlns="https://SampleSchema/AWContacts">

Imports <xmlns:s="sample-output">

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

Imports <xmlns:act="https://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 では、同じものが次のように記述されます。

<?xml version='1.0'?>

<xsl:stylesheet

  version="1.0"

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

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

  xmlns:s="sample-output"

  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">

    <s:PhoneNumberList>

      <xsl:apply-templates select="aw:Contact//act:telephoneNumber" />

    </s:PhoneNumberList>

  </xsl:template>

 

  <xsl:template match="aw:Contact//act:telephoneNumber">

    <s:PhoneNumber>

      <s:Number>

        <xsl:attribute name="type">

          <xsl:value-of select="name()" />

        </xsl:attribute>

        <xsl:value-of select="./act:number"/>

      </s:Number>

      <s:Owner>

        <xsl:value-of select="ancestor::aw:Contact/aw:FirstName"/>

        <xsl:text> </xsl:text>

        <xsl:value-of select="ancestor::aw:Contact/aw:LastName"/>

      </s:Owner>

    </s:PhoneNumber>

  </xsl:template>

</xsl:stylesheet>

VB チーム

投稿 : 2008 年 3 月 19 日 4:23 PM

分類 : LINQ/VB9OrcasVB2008Doug RothausXMLVB XML Cookbook

VB チームの Web ログ - https://blogs.msdn.com/vbteam/archive/2008/03/19/vb-xml-cookbook-recipe-2-descendants-and-ancestors-doug-rothaus.aspx (英語) より