VB XML 料理ブック レシピ 3 : ID 変換 (Doug Rothaus)
XSLT の ID 変換は、その名称が示すとおり、ある要素または属性の ID を新しい ID で置き換えます。ID 変換は、構造があまり固定されていない XML マークアップを操作するときに特に重要です。ニュース記事の文書構造を考えてみましょう。タイトルが記事内で参照されると、そのタイトルは斜体で強調表示されます。ただし、その記事の XML スキーマでは斜体は指定されていません。スキーマではその用語がある種のタイトルであることを指定し、他の変換がそれぞれのやり方でその用語を処理できるようにします。このような XML を HTML などの可読形式に変換する場合、本来の目的が損なわれないように、強調表示される用語の周囲のテキストの構造を保持する必要があります。例を示します。
<Paragraph sequenceID=”1”>This week a remastered version of the movie <title type=”movie”>Raider’s of the Lost Ark</title> was released.</Paragraph>
この XML は次のように変換されます。
<p>This week a remastered version of the movie <i>Raider’s of the Lost Ark</i> was released.</p>
ブラウザでは、次のように表示されます。
This week a remastered version of the movie Raider’s of the Lost Ark was released.
(メモ : 本当に公開されるかどうかは不明です。最初に頭に浮かんだものをタイプしただけです)
Visual Basic と XML リテラルを使用して ID 変換を実行するには、LINQ to XML オブジェクトの XML 軸プロパティと ReplaceWith メソッドを組み合わせます。
さらに複雑な例を見てみましょう。以前のレシピで使用した AdventureWorks の連絡先ソース ドキュメント (XML ドキュメントと関連スキーマは、「レシピ 1」の投稿からダウンロードできます) には、連絡先に関する電話番号や出荷先および請求先住所などの情報を格納する <AdditionalContactInfo> 要素があります。話を簡単にするため、<eMail> 要素だけを見ていきます。<eMail> 要素は、<AdditionalContactInfo> 要素の内容のいくつかの場所に登場します。このため、「レシピ 2」で説明した XML 子孫軸プロパティを使用して、<eMail> 要素へのすべての参照を検索できます。次に、クエリ結果を繰り返し処理して、各 <eMail> 要素に対して ReplaceWith メソッドを呼び出し、新しい ID で置き換えることができます。次に例を示します。
Dim emails = (From email In _
xmlDoc.<Contacts>.<Contact>.<aci:AdditionalContactInfo>...<act:eMail>).ToList()
For Each email In emails
TransformEmail(email)
Next
この例では、出力は HTML で、<eMail> 要素は電子メール アドレスへの mailto: リンクを指定するアンカー要素に置き換えられます。前のコード スニペットは <eMail> XElement オブジェクトを関数 TransformEmail に渡し、この関数が実際の置き換えを行います。
Private Sub TransformEmail(ByVal email As XElement)
Dim emailHtml = <div class="Email">
<a href=<%= "mailto:" & email.<act:eMailAddress>.Value %>>
<%= email.<act:eMailAddress>.Value %>
</a>
</div>
email.ReplaceWith(emailHtml)
End Sub
これらのサンプルを使用して HTML ドキュメントを作成する単純なクラスを次に示します。
Imports <xmlns="https://SampleSchema/AWContacts">
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 Recipe3
Public Function GetContactsHtml(ByVal xmlDoc As XDocument) As XElement
' Replace e-mail address tags with mailto links.
Dim emails = (From email In xmlDoc.<Contacts>.<Contact>.<aci:AdditionalContactInfo>...<act:eMail>).ToList()
For Each email In emails
TransformEmail(email)
Next
' Create the HTML document
Return <html>
<body>
<table border="1">
<%= From contact In xmlDoc.<Contacts>.<Contact> _
Select <tr>
<td valign="top">
<%= contact.<FirstName>.Value & " " & contact.<LastName>.Value %>
</td>
<td valign="top">
<%= contact.<aci:AdditionalContactInfo> %>
</td>
</tr> _
%>
</table>
</body>
</html>
End Function
Private Sub TransformEmail(ByVal email As XElement)
Dim emailHtml = <div class="Email">
<a href=<%= "mailto:" & email.<act:eMailAddress>.Value %>>
<%= email.<act:eMailAddress>.Value %>
</a>
</div>
email.ReplaceWith(emailHtml)
End Sub
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:aci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo"
xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
<xsl:output method="html" indent="yes"/>
<xsl:template match="aw:Contacts">
<html>
<body>
<table border="1">
<xsl:apply-templates select="aw:Contact" />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="aw:Contact">
<tr>
<td valign="top">
<xsl:value-of select="aw:FirstName"/>
<xsl:text> </xsl:text>
<xsl:value-of select="aw:LastName"/>
</td>
<td valign="top">
<xsl:apply-templates select="aci:AdditionalContactInfo" />
</td>
</tr>
</xsl:template>
<xsl:template match="aci:AdditionalContactInfo">
<div class="AdditionalInfo">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</div>
</xsl:template>
<xsl:template match="act:eMail">
<div class="Email">
<a>
<xsl:attribute name="href">
<xsl:text>mailto:</xsl:text>
<xsl:value-of select="act:eMailAddress" />
</xsl:attribute>
<xsl:value-of select="act:eMailAddress" />
</a>
</div>
</xsl:template>
</xsl:stylesheet>
要素の型でグループ化する
Visual Basic で利用できる 1 つの機能として、要素の型で変換をグループ化できます。たとえば、AdventureWorks のサンプルで使用している ContactTypes.xsd ファイルは、住所、電子メール、電話番号という型を定義しています。ContactTypes.xsd では、住所の型である 3 種類の要素名と、電話番号の型である 5 種類の要素名も識別します。XSLT では、住所の型ごとにテンプレートを作成するので、基本的に同じ形式になる情報に対して 3 種類のテンプレートが作成されます。Visual Basic では、異なる住所や電話番号の要素すべてに対して 1 つのクエリを作成し、XSLT テンプレートとして機能する同じ VB 関数に渡すことが簡単にできます。次に例を示します。
Dim addresses = (From addr In info...<act:homePostalAddress>).Union( _
From addr In info...<act:physicalDeliveryOfficeName>).Union( _
From addr In info...<act:registeredAddress>).ToList()
For Each address In addresses
TransformAddress(address)
Next
...
Private Sub TransformAddress(ByVal address As XElement)
Dim addressHtml = _
<div class="Address">
<%= address.<act:Street>.Value %><br/>
<%= address.<act:City>.Value & ", " %> 
<%= address.<act:StateProvince>.Value %> 
<%= address.<act:PostalCode>.Value %><br/>
<%= address.<act:CountryRegion>.Value %><br/>
<%= _
GetSpecialInstructions(address.<act:SpecialInstructions>.ToList()) %>
</div>
address.ReplaceWith(addressHtml)
End Sub
投稿 : 2008 年 4 月 25 日午前 11 時 19 分
VB チームの Web ログ - https://blogs.msdn.com/vbteam/archive/2008/04/25/vb-xml-cookbook-recipe-3-identity-transforms-doug-rothaus.aspx (英語) より