帳票出力にLINQを活用する(複数のXMLファイルを組み合わせて出力する)
複数のXMLファイルを組み合わせて出力する
次は、複数のXMLファイルに含まれるデータを組み合わせて1つの帳票に出力する例を紹介します。
「データの集合同士を結合する」という操作は、SQLに専用の構文が用意されているデータベースの世界では特に難しい操作ではありません。しかし、オブジェクトのコレクションやXMLドキュメントを結合する処理を結合したい場合、これまでの.NET言語ではコレクションをループで1つ1つ処理していくというやり方が主流でした。コレクションを処理するコードはループを多用するため、ネスト(入れ子構造)が深く、わかりにくいコードになってしまうことも少なくありません。
このようなデータソースの結合操作も、LINQを使うとすっきりしたコードにまとめることができます。
以下のデータはアドレス帳のデータと、アドレス帳に含まれるデータをグループ分けしたデータです。アドレス帳の各要素には番号、氏名、メールアドレスとグループ番号が、アドレスグループにはグループ番号とグループ名がそれぞれ定義されています。ここでも先ほどと同じように、「C:\ActiveReports3」フォルダにこれらの2ファイルが配置されているものとします。
<?xml version="1.0" encoding="UTF-8"?> <AddressBook> <Address> <AddressNo>1</AddressNo> <Name>山口</Name> <Email>yamaguchi@example.com</Email> <GroupNo>01</GroupNo> </Address> <Address> <AddressNo>2</AddressNo> <Name>新井</Name> <Email>arai@example.com</Email> <GroupNo>02</GroupNo> </Address> <Address> <AddressNo>3</AddressNo> <Name>中村</Name> <Email>nakamura@example.com</Email> <GroupNo>01</GroupNo> </Address> <Address> <AddressNo>4</AddressNo> <Name>松田</Name> <Email>matsuda@example.com</Email> <GroupNo>03</GroupNo> </Address> <Address> <AddressNo>5</AddressNo> <Name>高島</Name> <Email>takashima@example.com</Email> <GroupNo>02</GroupNo> </Address> </AddressBook>
<?xml version="1.0" encoding="UTF-8"?> <AddressGroups> <AddressGroup> <GroupNo>01</GroupNo> <GroupName>友人</GroupName> </AddressGroup> <AddressGroup> <GroupNo>02</GroupNo> <GroupName>職場</GroupName> </AddressGroup> <AddressGroup> <GroupNo>03</GroupNo> <GroupName>趣味</GroupName> </AddressGroup> </AddressGroups>
今回はこの2つを組み合わせて、次のような帳票を出力します。
この帳票を出力するために、次のような帳票レイアウトを作成します。
Detailセクションには番号、グループ、氏名、メールアドレスの各列にLabelコントロールを配置します。各LabelのDataFieldプロパティにはそれぞれ「AddressNo」「GroupName」「Name」「Email」を設定します。
このサンプルは、LINQのデータソースとしてXMLファイルを使用しますが、XMLを操作するためのLINQ(LINQ to XML)を使用するには、System.LinqのほかにSystem.Xml.Linq名前空間の参照を追加する必要があります。usingディレクティブ(Visual Basicの場合はImportsステートメント)を使って、ソースファイルの先頭に以下のコードを追加してください。
using System.Xml.Linq;
Imports System.Xml.Linq
問い合わせコードの記述
以下のコードは、2つのXMLファイルをデータソースとして使用し、結合結果をデータソースとして指定するコードです。LINQでXMLドキュメントを操作するには、主にSystem.Xml.Linq.XElementクラスのメソッドを使用することになります。
具体的には、XElementクラスのLoad()メソッドでXMLファイルを読み出し、Elements()メソッドでコレクションを指定します。そして、Element()メソッドとValueプロパティを組み合わせて、XMLドキュメントから値を取得します。
LINQで2つのデータを結合(内部結合)する場合は、fromクエリ句に続けて「join コレクション on 結合条件」の形で記述します。結合条件は「値1 equals 値2」の形で記述します。クエリが完成したら、これまでの例と同じようにToList()メソッドでListの形に変換します。
private void Form1_Load(object sender, EventArgs e) { NewActiveReport1 rpt = new NewActiveReport1(); string xmlFile1 = @"C:\ActiveReports3\AddressBook.xml"; string xmlFile2 = @"C:\ActiveReports3\AddressGroup.xml"; IEnumerable<XElement> xml1 = XElement.Load(xmlFile1).Elements("Address"); IEnumerable<XElement> xml2 = XElement.Load(xmlFile2).Elements("AddressGroup"); var query = from doc1 in xml1 join doc2 in xml2 on doc1.Element("GroupNo").Value equalsdoc2.Element("GroupNo").Value select new { AddressNo = doc1.Element("AddressNo").Value, Name = doc1.Element("Name").Value, Email = doc1.Element("Email").Value, GroupName = doc2.Element("GroupName").Value }; rpt.DataSource = query.ToList(); rpt.Run(); this.viewer1.Document = rpt.Document; }
Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim rpt As New NewActiveReport1 Dim xmlFile1 = @"C:\ActiveReports3\AddressBook.xml"; Dim xmlFile2 = @"C:\ActiveReports3\AddressGroup.xml"; Dim xml1 = XElement.Load(xmlFile1).Elements("Address"); Dim xml1 = XElement.Load(xmlFile2).Elements("AddressGroup"); Dim query = From doc1 In xml1 Join doc2 In xml2 On doc1.Element("GroupNo").ValueEquals doc2.Element("GroupNo").Value _ Select New With { _ .AddressNo = doc1.Element("AddressNo").Value, _ .Name = doc1.Element("Name").Value, _ .Email = doc1.Element("Email").Value, _ .GroupName = doc2.Element("GroupName").Value _ } rpt.DataSource = query.ToList() rpt.Run() Me.Viewer1.Document = rpt.Document End Sub
コードを書き終えたらアプリケーションを起動して、帳票のプレビューを表示してみましょう。2つのXMLファイルに格納されたデータがLINQによって結合され、1つの帳票として出力できました。
まとめ
今回は、Visual Studio 2008に対応したActiveReports 3.0の新機能として、ActiveReports用の新しいプロジェクトテンプレートとLINQの活用法を中心に紹介しました。
次回は「帳票アプリケーション開発におけるテスト」というテーマでお送りする予定です。お楽しみに。