Zen レポート・クラスの構築
“Zen レポートの概要” の章の “Zen レポートのチュートリアル” のセクションでは、Zen レポートが %ZEN.Report.reportPageOpens in a new tab の拡張クラスであることを説明しています。“Zen レポートのチュートリアル” では、順を追ってクラスを構築することにより、Zen レポート・クラスの構造について説明しています。
この他には、XData ReportDescription ブロックと XData ReportDisplay ブロックを記述して、Zen レポート・クラスでレポート出力を XHTML や PDF フォーマットで生成する方法について説明している章があります。“Zen レポートのデータの収集”、“Zen レポートのページのフォーマット”、および “Zen レポートのデータの表示” の各章がこのような章に該当します。
この章では、これらの章で得られた基礎知識をベースとして、Zen レポート・クラスの構造と構成についてより詳しく説明します。項目は以下のとおりです。
パラメータによる Zen レポートの制御
パラメータという用語は包括的に使用されています。このセクションでは、Zen レポート・クラスの動作を変更するために使用可能な数種類のパラメータについて説明します。いずれの場合も、Zen レポートの制御に使用する場合はその項目をパラメータと呼んでいますが、パラメータの使用におけるコンテキストや構文は、その都度異なります。
クラス・パラメータ
クラス・パラメータは、Zen レポート・クラスで使用可能な ObjectScript の規約です。概要については、"Caché オブジェクトの使用法" の “Caché クラス” の章の “クラス・パラメータ” を参照してください。
“Zen レポートの概要” の章の “Zen レポートのチュートリアル” のセクションでは、クラス・パラメータの APPLICATION、DEFAULTMODE、および REPORTXMLNAMESPACE を紹介しました。これらは、スタジオで新しく Zen レポート・クラスを作成する際に、Zen レポート・ウィザードによって自動的に指定されます。Zen レポート・クラスでは、他にも多くのクラス・パラメータがサポートされています。詳細は、付録 “Zen レポート・クラスのパラメータ” の以下のセクションを参照してください。
-
“一般的に使用するクラス・パラメータ” では、Zen レポートの一般的な処理命令について説明します。
-
“XSLT スタイルシートのクラス・パラメータ” では、その他の特殊な XSLT 処理命令について説明します。この一連のパラメータにより、ブラウザが Internet Explorer の場合で、Zen レポート・クラスの CSP クラス・パラメータ PRIVATE を 1 (True) に設定することによって、Zen レポート・クラスをプライベートとしてマークしている場合に発生する問題に対処できます。このような問題がない場合は、これらの特殊なクラス・パラメータを使用する必要はありません。
SQL クエリ・パラメータ
Zen レポートにデータを入力する SQL クエリを指定する場合、クエリには SQL パラメータを含めることができます。これは、Zen ページと同様に Zen レポートでもサポートされています。以下は、パラメータを取る SQL クエリの例です。? 文字は、クエリ内のパラメータのプレースホルダです。
SELECT ID,Customer,Num,SalesRep,SaleDate FROM ZENApp_Report.Invoice WHERE (Month(SaleDate) = ?) OR (? IS NULL) ORDER BY SalesRep,SaleDate
以下は、? プレースホルダに値を提供するために <parameter> 要素で sql 属性を使用してデータを指定する、Zen レポートの例です。
クエリ内の ? プレースホルダごとに、個別の <parameter> 要素が必要です。
<report
xmlns="http://www.intersystems.com/zen/report/definition"
name="myReport"
sql="SELECT ID,Customer,Num,SalesRep,SaleDate
FROM ZENApp_Report.Invoice
WHERE (Month(SaleDate) = ?) OR (? IS NULL)
ORDER BY SalesRep,SaleDate"
orderby="SalesRep,Customer" >
<!-- Supply values to the ? query parameters here -->
<parameter expression='..Month'/>
<parameter expression='..Month'/>
<!-- Other report contents appear here -->
</report>
SQL クエリとそのパラメータに関する詳細は、“Zen レポートのデータの収集” の章の “<report> または <group> でのクエリの作成” のセクションを参照してください。
データ型パラメータ
データ型パラメータは、Zen レポート・クラスで使用可能な ObjectScript の規約です。概要については、"Caché オブジェクトの使用法" の “データ型” の章の “パラメータ” を参照してください。
Zen レポートの最も便利なデータ型パラメータは、ZENURL です。開発者が ZENURL パラメータを Zen レポート・クラスのプロパティに割り当てると、ユーザは Zen レポートを呼び出す際に URI にクエリ・パラメータを指定することで、実行時にそのプロパティの値を設定することができます。ZENURL 値により、URI クエリ・パラメータに名前を付けます。規約により、ドル記号 (“$”) で始まる ZENURL 値は、定義済みの URI クエリ・パラメータ ($MODE など) のために予約されています。次に例を示します。
Property employeeID As %ZEN.Datatype.string(ZENURL="ID");
詳細は、“Zen レポートの実行” の章の “URI による Zen レポート・クラスのプロパティの設定” を参照してください。
XSLT スタイルシート・パラメータ
ユーザは、Zen レポート・クラスを呼び出す際に URI クエリ・パラメータを使用して、XSLT スタイルシート・パラメータ値を Zen レポートに渡すことができます。この方法で定義されたパラメータは、XData ReportDisplay の <report> 要素内の XSLT グローバル変数になります。この規約では、XData ReportDisplay ブロック内の <xslt> 要素と、ZENURL データ型パラメータが定義された少なくとも 1つのプロパティを持つ Zen レポート・クラスのプロパティとの調整を慎重に行う必要があります。
詳細と完全な例は、“Zen レポートのページのフォーマット” の章の “<xslt>” を参照してください。
URI クエリ・パラメータ
ZENURL を使用して定義できる URI クエリ・パラメータに加え、Zen レポートでは定義済みの URI クエリ・パラメータがいくつか用意されています。これらを実行時に使用して、対応する Zen レポート・クラスのパラメータによって設定されている値をオーバーライドすることができます。規約により、これらのパラメータの名前はドル記号 (“$”) で始まります。
次の例では、URI 文字列に $MODE パラメータを使用して、Zen レポート・クラス内の DEFAULTMODE パラメータに設定されているすべての値をオーバーライドします。以下の $MODE=pdf の値により、出力のタイプを PDF に変更します。
http://localhost:57772/csp/myPath/myApp.myReport.cls?$MODE=pdf
使用可能な URI パラメータおよびそれらに対応するクラス・パラメータの概要は、“Zen レポートの実行” の章の “Zen レポートの URI クエリ・パラメータ” を参照してください。
Zen レポートでの実行時式の使用法
実行時式は、Zen レポート・クラスの XData ReportDisplay ブロックで使用できます。使用するには、 #()# コンテナに式を記述するだけです。この規約を使用して参照できるのは、以下の項目のみです。
-
Zen レポート・クラスのプロパティ。
以下の例では、実行時式を使用して、XData ReportDisplay の <item> が持つ field 属性にクラス・プロパティ username の値を割り当てています。#()# コンテナの中では、二重ドット構文を使用してプロパティを参照します。そのプロパティには、このクラスまたはそのスーパークラスのいずれかで定義している任意のプロパティを以下のように指定できます。
<item field="#(..username)#" />
上記の例では、プロパティの値を属性に割り当てています。また、この値は、以下の例で示す <p> などの要素のコンテンツとして割り当てることもできます。さらに以下の例では、ObjectScript 規約を使用して通常のテキストにプロパティの値を連結する方法を示しています。
<p>#("The current user is " _ ..username)#</p>
-
ObjectScript 式。
実行時式には、値に解決できるものであれば ObjectScript 式を指定できます。以下の例では、実行時式を使用して、XData ReportDisplay の <item> が持つ field 属性に、計算した時刻値を割り当てています。
<item field="#($ZDATETIME($HOROLOG,3))#" />
同様に、この値は、以下の例で示す <p> などの要素のコンテンツとして割り当てることもできます。
<p>#($ZDATETIME($HOROLOG,3))#</p>
-
特殊変数 %display。
%display は、XData ReportDisplay にある最上位の <report> コンテナを表します。%display オブジェクトのプロパティは、<report> 要素の属性に対応します。例えば、<report> の title 属性を以下のように定義しているとします。
XData ReportDisplay [ XMLNamespace = "http://www.intersystems.com/zen/report/display" ] { <report xmlns="http://www.intersystems.com/zen/report/display" title='Help Desk Sales Report' style='standard'> <!-- OTHER PARTS OF THE REPORT --> </report> }
XData ReportDisplay の他の部分にある <report> コンテナでは、以下の例のように実行時式 #(%display.title)# を使用して <report> の title 属性値を表現できます。
XData ReportDisplay [ XMLNamespace = "http://www.intersystems.com/zen/report/display" ] { <report xmlns="http://www.intersystems.com/zen/report/display" title='Help Desk Sales Report' style='standard'> <body> <header> <p class="banner1">#(%display.title)#</p> </header> <!-- OTHER PARTS OF THE REPORT --> </body> </report> }
“コードを再利用するための Zen レポートの構成” セクションでは、メインの Zen レポート・クラスの XData ReportDisplay から参照できるコードの再利用可能な部分を、複合クラスとテンプレートを使用して定義する方法を説明します。実行時式は、複合クラスおよびテンプレート・クラスで機能します。これは、複合クラスやテンプレートにある XData 情報が、それらを参照する XData ReportDisplay で生成したコードに実行時に統合されるためです。複合クラスまたはテンプレート・クラスに記述したすべての実行時式は、上位レベルの XData ReportDisplay ブロックの一部になります。
実行時式の #()# 構文は、XData ReportDefinition ブロックでは機能しません。
XData ReportDefinition や XData ReportDisplay では、実行時式の #()# コンテナを利用せずに式を使用できる要素が数多くあります。このような要素には以下のものがあります。
-
XData ReportDefinition の expression、breakOnExpression、および filter の各属性。詳細は、“Zen レポートのデータの収集” を参照してください。
-
XData ReportDisplay の要素で使用できる expression 属性および条件式の属性。詳細は、“Zen レポートのページのフォーマット” を参照してください。
Zen レポートのローカライズ
ドキュメント "Zen アプリケーションの開発" の “Zen のローカライズ” の章では、Zen アプリケーションでさまざまな言語ロケールに翻訳済みテキストを適用する方法について説明します。この概念は、Zen レポートにも適用できます。
メッセージ・ディクショナリへのエントリの追加
Zen レポートのコードの中で Zen のデータ型 %ZEN.Datatype.captionOpens in a new tab または $$$Text マクロを使用している場所であれば、対応するテキスト値は該当の Caché ネームスペースでメッセージ・ディクショナリのエントリになります。そこから翻訳するテキスト値をエクスポートできます。翻訳したテキストを Caché メッセージ・ディクショナリにインポートして戻し、アプリケーションのローカライズに使用できます。
ローカライズは、Zen レポート・クラスで DOMAIN パラメータに空でない文字列を定義している場合にのみ機能します。同じローカライズ DOMAIN にある各クラスのメッセージは、Caché ネームスペースのメッセージ・ディクショナリにまとめて格納されます。
Zen レポート・コンポーネントの多くの属性は既に %ZEN.Datatype.captionOpens in a new tab タイプになっているので、自動的にローカライズがサポートされています。このドキュメントの各属性の説明では、この扱いに該当するかどうかを示しています。ObjectScript がサポートされている場所であれば、Zen レポートの実行時式の値などの $$$Text マクロを使用できます。さらに、Zen レポート・クラスには、$$$Text マクロを呼び出すショートカットが用意されています。このショートカットは、Zen レポート・クラスの XData ReportDisplay ブロックでのみ使用可能です。
その構文は以下のとおりです。
<item value="@footertime@Created on: " />
以下を使用して、該当の Caché ネームスペースで使用するメッセージ・ディクショナリのエントリを作成します。
-
メッセージ・テキスト "Created on: " — 他の言語に翻訳するテキストです。
-
メッセージ識別子 "footertime" — Caché のローカライズ機能では、この識別子を使用して翻訳済みテキストを検索します。
$$$Text マクロを使用する場合とは異なり、2 つの @ を記述したショートカットを使用する場合は、各メッセージ識別子 (この例では "footertime") がローカライズ DOMAIN 全体で一意であることをユーザ側で確認する必要があります。
2 つの @ を使用したショートカットは、特殊変数 %response.Language を正しく設定している場合にのみ機能します。そのためには、Zen レポート・クラスで %OnBeforeReport コールバック・メソッドに以下の文を記述します。このメソッドは、レポートを表示する前に自動的に実行されます。
Method %OnBeforeReport() As %Status
{
Set %response.Language =
##class(%MessageDictionary).MatchLanguage($$$SessionLanguage,"ZenReport")
Quit $$$OK
}
Excel 出力のローカライズ
“Excel スプレッドシート出力向け Zen レポートの設定” のセクションでは、Zen レポートを使用して Excel スプレッドシートを作成する方法について説明します。スプレッドシートを作成すると、<element> の excelName 属性によりスプレッドシートの列ヘッダにテキストが提供されます。必要な特殊構造を持つ ReportDefinition ブロックを使用すると、excelName により自動的に列ヘッダのテキストをメッセージ・ディクショナリに置くことでローカライズがサポートされます。ReportDisplay ブロックを使用して任意の形式で XML から Excel スプレッドシートを作成する場合、列ヘッダのテキストをローカライズするのにいくつかの追加手順を行う必要があります。
-
このようなレポートには出力モード displayxlsx が必要なため、DEFAULTMODE または $MODE を適切に設定する必要があります。また DOMAIN パラメータを設定する必要もあります。DOMAIN は任意のテキスト文字列であり、メッセージ・ディクショナリ内のエントリとそれらエントリを生成したクラスとを一致させるのに使用します。DOMAIN を設定しないとローカライズは機能しません。
Parameter DEFAULTMODE As STRING = "displayxlsx"; Parameter DOMAIN As STRING = "SKISC";
-
以下のサンプル・コードにあるように、レポートの XML を指定する ReportDefinition ブロックを作成します。
XData ReportDefinition [ XMLNamespace = "http://www.intersystems.com/zen/report/definition" ] { <report xmlns="http://www.intersystems.com/zen/report/definition" name="MyReport" sql="SELECT TOP 10 Name,DOB,Age FROM Sample.Person" runtimeMode="0"> <group name="Person"> <attribute name="name" field="Name"/> <attribute name="dob" field="Dob" expression="..ToExcelDate(%val)"/> <attribute name="age" field="Age"/> </group> </report> }
-
Excel 出力のレポートのフォーマット処理を行う ReportDisplay ブロックを定義します。excelName の値の最初にある “$$$” はローカライズの当該テキスト値を表します。
XData ReportDisplay [ XMLNamespace ;= "http://www.intersystems.com/zen/report/display" ] { <report xmlns="http://www.intersystems.com/zen/report/display" name="MyReport"> <body> <table group="Person" excelSheetName="Persons" excelGroupName="Person" oldSummary="false"> <item field="@name" excelName="$$$Name" /> <item field="@dob" isExcelDate="true" excelName="$$$Date of Birth" /> <item field="@age" isExcelNumber="true" excelName="$$$Age"> </item> </table> </body> </report> }
ReportDefinition と ReportDisplay でレポートの名前は同じである必要があります。
-
$$$ 式の ^CacheMsg グローバルのエントリを生成するには、ヘルパー ClassMethod を記述します。レポートのコンパイル時にエントリが生成されます。
ClassMethod Translations() { set x=$$$Text("Name") set x=$$$Text("Date of Birth") set x=$$$Text("Age") }
-
CacheMsg をエクスポートします。
DO ##class(%Library.MessageDictionary).ExportDomainList("C:\Temp\local.xml","SKISC")
-
エクスポートしたメッセージ・ディクショナリ・ファイルを変換し、ローカライズ・バージョンを保存します。
-
変換をインポートします。
DO ##class(%Library.MessageDictionary).Import("C:\Temp\local_de.xml")
コードを再利用するための Zen レポートの構成
いくつかの Zen レポートを設計している中で、ページのデザインを部分的に他のレポートでも再利用できると便利なことがあります。再利用によって、関連するレポート間の一貫性を確保できるほか、開発期間を短縮できることが普通です。Zen レポートでは、XData ReportDisplay ブロックでの再利用を実現する方法として複合クラスとテンプレートが用意されています。両者の大きな違いは、複合クラスは実行時にパラメータを受け取ることができるのに対し、テンプレートは完全に静的であることです。
SAMPLES ネームスペースでは、ZENApp パッケージに詳細なコード例が用意されています。Zen レポート・クラス ZENApp.MyReport.cls と同じ体裁が得られるレポートが ZENApp.CompositeReport.cls で定義されていますが、こちらはレポートの構成で複合クラスとテンプレートを使用しています。ZENApp.CompositeReportOpens in a new tab パッケージには、ZENApp.CompositeReport.cls で参照する複合クラスやテンプレートを定義したクラスがいくつか収録されています。
以下のテーブルは、複合クラスとテンプレートの簡単な比較です。
拡張 | XData ブロック | 最上位のコンテナ要素 | 詳細 |
---|---|---|---|
%ZEN.Report.Display.compositeOpens in a new tab | Display | <composite> | “Zen レポートの複合クラスの使用法” |
%ZEN.Report.Display.reportTemplateOpens in a new tab | (任意の名前) | <template> | “Zen レポートのテンプレートの使用法” |
Zen レポートの複合クラスの使用法
このトピックでは、Zen レポートの一貫性と再利用性を実現するために別途定義して繰り返し参照する Zen レポートの構文ブロックを複合クラスといいます。XData ReportDisplay ブロックの任意の部分を複合クラスで定義できます。例えば、普通は <document>、<body>、または <report> の各コンテナに記述する要素の定義が可能です。これは、テンプレートでも同様です。テンプレートと異なるのは、実行時に値を指定するパラメータを複合クラスで使用できる点です。これらのパラメータは、複合クラスのプロパティとして定義する必要があります。Zen レポート・クラスの XData ReportDisplay ブロックで複合クラスを参照するときに、これらのプロパティの値を指定します。
このトピックの以下のセクションでは、この方法が機能するうえで必要なすべての手順を説明します。
複合クラスで定義している各プロパティに変更がなければ、その複合クラスを変更してリコンパイルしても、その複合クラスを参照しているクラスをリコンパイルする必要はありません。複合クラスの変更は、実行時に取得されます。
Zen レポートの複合クラスは、XData Display ブロックが属する %ZEN.Report.Display.compositeOpens in a new tab のサブクラスです。テンプレートとは異なり、すべての複合クラスの定義ブロックの名前は同じで、XData Display とする必要があります。XData Display ブロックには、複合クラスの定義があります。この定義は、その複合クラスを参照する XData ReportDisplay ブロックで生成したコードに適用されます。XData Display ブロックのほか、複合クラスでもプロパティを定義できます。これらのプロパティの目的は、複合クラスに値を渡して、XData Display 定義の詳細を実行時に変更できるようにすることです。
“スタイルを定義する複合クラスの作成” および “レイアウトを定義する複合クラスの作成” の各セクションでは、%ZEN.Report.Display.compositeOpens in a new tab クラスの内容について詳しく説明します。
スタイルを定義する複合クラスの作成
以下の図では、<document> コンテナに配置するスタイル・クラスの定義を目的とする %ZEN.Report.Display.compositeOpens in a new tab クラスの主要部分を取り上げています。この図の後に詳しい説明があります。
-
複合クラスは、%ZEN.Report.Display.compositeOpens in a new tab クラスの拡張とする必要があります。
-
クラスによって NAMESPACE パラメータを定義する必要があります。このパラメータには、任意の値を指定できます。
-
XData ブロックの名前は必ず Display とします。
-
XData Display ブロックでは、XMLNamespace キーワードに以下の値を指定する必要があります。
http://www.intersystems.com/zen/report/display
-
XData Display の最上位コンテナ要素は、<composite> である必要があります。xmlns 属性値を指定できますが、値は XMLNamespace キーワードと同じでも異なっていてもかまいません。
-
<composite> コンテナの補足の XML ネームスペース名を、以下のように xmlns: 属性構文を使用して定義します。この新しいネームスペースは、別のクラスからこの複合クラスを参照する場合に重要になります。これは NAMESPACE パラメータで使用した値と同じ値になります。以下の例では、この新しいネームスペースを mystyle としています。
-
この例に示す複合クラスの目的は、Zen レポートの <document> コンテナで指定する各種スタイルを定義することです。時間と共に、スタイルの複合クラスのライブラリがしだいに大きなサイズになる可能性があります。これらのクラスとその参照を容易に管理できるようにクラスの命名規則を簡潔にするには、クラス自体の単純な名前に基づいてスタイル名を作成することをお勧めします。この例では、テーブル・ヘッダのスタイルの名前 th.mygroupheader は、そのクラスの単純な名前 mygroupheader に基づいています。
-
複合クラスをコンパイルすると、その単純なクラス名 (この例では、mygroupheader) は、Zen レポート・クラスの XData ReportDisplay ブロックに記述できる XML 要素の名前になります。これにより、複合クラスを参照し、そのコンテンツを XData ReportDisplay ブロックの該当位置に配置できます。参照を記述する際の正しいネームスペースの使用などの構文に関する詳細は、“Zen レポートでの複合クラスの参照” セクションを参照してください。
レイアウトを定義する複合クラスの作成
以下の図では、<report> に配置する <pagefooter> の定義を目的とする %ZEN.Report.Display.compositeOpens in a new tab クラスの主要部分を取り上げています。この図の後に詳しい説明があります。
-
ベース・クラス、XData ブロックの名前、XMLNamespace キーワードの値、最上位コンテナ、および xmlns 属性の基本特性は、“スタイルを定義する複合クラスの作成” のセクションにおける説明と同じです。
-
この例に示す複合クラスの目的は、<report> の <pagefooter> で指定する場所に適用するレイアウトを定義することです。複合クラスには、3 つのプロパティが用意されています。複合クラスのすべてのプロパティは、例で示すように、Zen データ型で定義する必要があります。以下のように、このプロパティを単純に定義した場合は、その複合クラスを参照する際にそれらを属性として扱います。
Property username As %ZEN.Datatype.string;
以下のように、プロパティに XMLPROJECTION を割り当てて "element" に設定した場合は、複合クラスを参照する際にそれらを要素として扱います。
Property username As %ZEN.Datatype.string(XMLPROJECTION = "element");
プロパティの投影方法に関係なく、複合クラスの XData Display ブロックの中では各プロパティの参照は以下の形式になります。
#(..property_name)#
この参照を指定する #()# 構文は複合クラス独特のものではなく、これが Zen レポートの式であることを示す構文です。構文に関する詳細は、“Zen レポートでの実行時式の使用法” を参照してください。#()# コンテナでは、二重ドット構文でクラスのプロパティを参照します。property_name はプロパティの名前です。例に挙げた複合クラスの XData Display ブロックで username プロパティを参照する行の全体は以下のようになります。
<item field="#(..username)#" />
複合クラスでこのような実行時式を使用する場合、その複合クラスでは、<item> の field 属性の値として適切に機能する username プロパティの値が呼び出し元の Zen レポートから送信されることを想定しています。次のセクション “Zen レポートでの複合クラスの参照” では、この関係の正しい例を示します。Zen レポートから複合クラスに送信したプロパティ値がその複合クラスに適していない場合、対応するレポートのセクションは正常に機能しません。
-
Zen レポートを他の言語にローカライズする必要がある場合は、複合クラスのローカライズを有効にする必要があります。そのためには、DOMAIN パラメータを空ではない値に設定し、テキストの値でローカライズ構文を必要に応じて使用します。例にある 2 つの @ を使用した構文の詳細は、“Zen レポートのローカライズ” を参照してください。
-
複合クラスをコンパイルすると、その単純なクラス名 (この例では、ReportFooter) は、Zen レポート・クラスの XData ReportDisplay ブロックに記述できる XML 要素の名前になります。これにより、複合クラスを参照し、そのコンテンツを XData ReportDisplay ブロックの該当位置に配置できます。参照を記述する際の正しいネームスペースの使用や複合クラスのプロパティ値の指定方法などの構文に関する詳細は、“Zen レポートでの複合クラスの参照” セクションを参照してください。
Zen レポートでの複合クラスの参照
以下の図では、いくつかの複合クラスを参照する Zen レポート・クラスの XData ReportDisplay ブロックを取り上げています。この複合クラスには、前のセクションの “スタイルを定義する複合クラスの作成” および “レイアウトを定義する複合クラスの作成” で定義したものもあります。図の後の説明では、図中の番号の部分について詳しく説明しています。
-
<report> 要素では、参照する複合クラスごとに NAMESPACE パラメータ値と一致する XML ネームスペース接頭語を定義する必要があります。そのためには、xmlns: 属性構文を使用します。この例では、スタイル複合クラスにネームスペース接頭語 mystyle を指定し、レイアウト複合クラスにネームスペース接頭語 my を指定しています。この使い分けは任意ですが、複合クラスの構成方法として合理的です。
各ネームスペース接頭語に割り当てる URI の値は、対応する複合クラスで指定している NAMESPACE および <composite> の定義に沿ったものとする必要があります。“スタイルを定義する複合クラスの作成” および “レイアウトを定義する複合クラスの作成” に示す値と、ここに示す値を比較してください。
XData ReportDisplay [ XMLNamespace = "http://www.intersystems.com/zen/report/display" ] { <report xmlns="http://www.intersystems.com/zen/report/display" xmlns:mystyle="http://www.intersystems.com/zen/report/display/my/style" xmlns:my="http://www.intersystems.com/zen/report/display/my"> <!-- CONTENTS OF REPORT HERE --> </report> }
-
複合クラスを参照する場合、その名前を XData ReportDisplay の中の XML 要素として使用します。複合クラス名の前にネームスペース接頭語とコロン文字を付加します。以下の例では、ネームスペース接頭語 mystyle と複合クラス名 mygroupheader を使用しています。mygroupheader 複合クラスで使用する構文を確認するには、“スタイルを定義する複合クラスの作成” を参照してください。以下のとおり、この複合クラスにプロパティはありません。
<mystyle:mygroupheader />
この参照によって、mygroupheader 複合クラスの <composite> と </composite> の間にあるコード全体が、XData ReportDisplay ブロックの指定の場所に配置されます。
-
ここでは、ネームスペース名 my と複合クラス名 ReportFooter を使用しています。ReportFooter 複合クラスで使用する構文を確認するには、“レイアウトを定義する複合クラスの作成” を参照してください。この複合クラスには、class、timestamp、および username の 3 つのプロパティがあります。
<my:ReportFooter class="table.mygroupfooter" timestamp="@timestamp" username="@username" />
この参照によって、ReportFooter 複合クラスの <composite> と </composite> の間にあるコード全体が、XData ReportDisplay ブロックの指定の場所に配置されます。ReportFooter から配置するとき、複合クラスで class、timestamp、および username の各プロパティを参照している場所には、XData ReportDisplay で割り当てた値が代入されます。
-
XML 属性として投影される ReportFooter クラスのすべてのプロパティについて、その名前の属性を指定し、プロパティに必要な値を設定します。以下はその例です。
<my:ReportFooter class="table.mygroupfooter" timestamp="@timestamp" username="@username" />
この例では、class の値はリテラル文字列です。timestamp および username の値は、同じ Zen レポート・クラスにある XData ReportDefinition ブロックで生成した XML の属性から取得します。そのため、これらには XPath @ 構文を使用します。また、複合クラスのどの属性の値にも Zen レポートの実行時式を使用できます。
Zen データ型を指定して定義した複合クラスのプロパティは、自動的に属性として XML に投影されます。これらのプロパティを XML 要素として投影するには、プロパティの定義方法と参照方法を変更する必要があります。複合クラスで以下を指定しているとします。
Property username As %ZEN.Datatype.string;
これを以下の指定に変更します。
Property username As %ZEN.Datatype.string(XMLPROJECTION = "element");
要素としてプロパティを投影している場合は、複合クラスを参照する構文が異なります。ReportFooter のプロパティが以下のようになっているとします。
Property class As %ZEN.Datatype.string; Property timestamp As %ZEN.Datatype.string; Property username As %ZEN.Datatype.string(XMLPROJECTION = "element");
この場合、XData ReportDisplay で ReportFooter 複合クラスを参照するには以下のように記述します。
<my:ReportFooter class="table.mygroupfooter" timestamp="@timestamp"> <my:username>@username</my:username> </my:ReportFooter>
Zen レポートのテンプレートの使用法
このセクションで説明するテンプレート機能は、XSLT テンプレートとは関係ありません。“Zen レポートへの XSLT テンプレートの指定” と比較してください。
このトピックでは、Zen レポートの一貫性と再利用性を実現するために別途定義して繰り返し参照する Zen レポートの構文ブロックをテンプレートといいます。XData ReportDisplay ブロックの任意の部分をテンプレートで定義できます。例えば、<document> ブロックや <body> ブロックを部分的に定義可能です。これは、複合クラスでも同様です。複合クラスと異なる点は、テンプレートは完全に静的で、パラメータを受け取ることはできないことです。テンプレートでは、コードの単純な置換ができます。
表示要素 (<header> や <footer> など) をテンプレートとして定義できます。これにより、XData ReportDisplay 定義の <body> ブロックにその表示要素を配置する際に、定義済みのテンプレートを参照できます。その要素のすべての属性またはその他の子要素が、その要素のテンプレート定義全体に置き換わります。
Zen レポートのテンプレートの作成
Zen レポートのテンプレートは、XData ブロックを含む %ZEN.Report.Display.reportTemplateOpens in a new tab のサブクラスです。XData ブロック内には、テンプレート名と定義が含まれます。以下は、Header1 というテンプレートを定義する Zen レポートのテンプレート・クラスの例です。
Class ZENApp.HeaderTemplate Extends %ZEN.Report.Display.reportTemplate
{
XData Header1
[ XMLNamespace = "http://www.intersystems.com/zen/report/display" ]
{
<template>
<header>
<p class="banner1">HelpDesk Sales1 Report</p>
<fo><line pattern="empty"/><line pattern="empty"/></fo>
<table orient="row" width="3.45in" class='table1'>
<item value="Sales by Sales Rep" width="2in">
<caption value="Title:" width="1.35in"/>
</item>
<item field="@month" caption="Month:"/>
<item field="@author" caption="Author:"/>
<item field="@runBy" caption="Prepared By:"/>
<item field="@runTime" caption="Time:"/>
</table>
</header>
</template>
}
}
テンプレートは、実行時にのみインスタンス化されます。テンプレートを定義するときに実行時式やデータ項目を使用できます。ただし、テンプレートに使用している実行時式やデータ項目は、テンプレート・クラス自体では評価できず、テンプレートを呼び出すレポートや複合クラスのコンテキストで評価されます。前述のテンプレート例は、参照しているデータ項目 (@month、@author、@runBy、および @runTime) が、対応する XData ReportDefinition ブロックで生成した XML データに実際に存在する場合にのみ機能します。
Zen レポートのテンプレートの参照
以下の構文例は、前のセクションで取り上げたサンプル・テンプレートを参照しています。
<header template="ZENApp.HeaderTemplate:Header1" />
レポートに表示するコンテンツを指定する各要素、つまり <body> ブロックで指定できる各要素では、template 属性がサポートされています。表示要素のリストを確認するには、“Zen レポートのページのフォーマット” の章の <report> および <body> のセクションを参照してください。以下のテーブルでは、これらすべての要素でサポートされている template 属性を説明します。
属性 | 意味 |
---|---|
template |
XData ReportDisplay で属性やその他のコンテンツを直接指定するのではなく、この要素を指定するために使用可能なテンプレートを指定します。template 値の形式は以下のとおりです。 templateClass:templateName 以下はその説明です。
|
通常、テンプレートを参照する場合、要素には template 以外の属性を指定しません。Zen では、template 属性と共に指定されたその他の属性の値は無視されるためです。上記の例の <header> 要素で、次のように width 属性も指定したとしましょう。
<header template="ZENApp.HeaderTemplate:Header1" width="7.25in" />
Zen では、この width 属性の値は無視され、代わりに Header1 テンプレート定義で指定されている幅の特性が、内容にかかわらず使用されます。テンプレートに width 値が見つからない場合、<header> 要素に指定した width 属性ではなく、Zen の既定値の幅が使用されます。
次の XData ReportDisplay ブロックのサンプルでは、この <header> 要素例を完全なコンテキストで示します。また、目的の出力が PDF であるため、この例では <document> 要素も指定しています。
XData ReportDisplay
[ XMLNamespace = "http://www.intersystems.com/zen/report/display" ]
{
<report xmlns="http://www.intersystems.com/zen/report/display"
name='myReport' title='HelpDesk Sales Report' style='standard'>
<document width="8.5in" height="11in"
marginLeft="1.25in" marginRight="1.25in"
marginTop="1.0in" marginBottom="1.0in"
referenceOrientation="0">
</document>
<body>
<header template="ZENApp.HeaderTemplate:Header1"/>
<!-- OTHER ELEMENTS OF THE REPORT DISPLAY -->
</body>
</report>
}
Zen レポートへの XSLT テンプレートの指定
このセクションで説明する機能は、特に XSLT テンプレートに関係しています。さまざまなレポートで Zen レポートの構文セクションを再利用できる一般的な機能については、“Zen レポート・クラスの構築” の “Zen レポートのテンプレートの使用法” を参照してください。
XSLT に精通している場合、<xsl:call-template> 構文を使用して、XSLT 変換内の特定のテンプレートを呼び出した経験があるかもしれません。<xsl:call-template> を使用すると、テンプレートを呼び出すときにパラメータや値をテンプレートに渡すことができます。表示要素では同様の規約がサポートされています。
Zen レポート・クラスでは、ReportDefinition および ReportDisplay と呼ばれる XData ブロックに加え、XSLT テンプレートを含むことのできる 3 つの XData ブロックがサポートされています。以下のテーブルはその一覧です。
使用する XData ブロック名 (大文字と小文字を区別)… | XSLT テンプレートを適用する対象… |
---|---|
XData HtmlXslt | すべての XHTML 出力 |
XData XslFoXslt | すべての PDF 出力用 XSL-FO |
XData AllXslt | すべての出力 |
<xsl:template> を複数使用する必要がある場合、それらを <zenxslt> 要素で囲うことができます。<zenxslt> の詳細は、"<xslt> で参照する XData ブロック" を参照してください。XSLT テンプレートが格納される XData ブロックは、同じレポート・クラスに配置して使用することも、別々のレポート・クラスに配置して多数のレポートで使用することもできます。
以下の Zen レポート・クラスからの抜粋では、XSLT テンプレートは空のため何も実行されません。この例では、単に XSLT テンプレートを XData ブロック内に配置する方法を示しています。以下の <xsl:template> コンテナ内には、任意の該当する XSLT 文を配置できます。
XData HtmlXslt {
<xsl:template name="htmExample" >
</xsl:template>
}
XData XslFoXslt {
<xsl:template name="pdfExample" >
</xsl:template>
}
XData AllXslt {
<xsl:template name="allExample" >
</xsl:template>
}
XData HtmlXslt および XData XslFoXslt の <xsl:template> コンテナの name には、同じ name 値を指定できます。なぜなら、この 2 つの XData ブロックは一緒に使用されることがないためです。両方の出力形式に必要な XSLT テンプレートがある場合は、それを XData AllXslt に配置します。
スタイルを適用する XSLT テンプレートの呼び出し
XSLT テンプレートの一般的な使用方法の 1 つに、スタイルを適用するテンプレートを呼び出すことがあります。呼び出す適切な XSLT テンプレートは、出力形式によって異なります。以下のように、両方の出力固有ブロックで同じ名前を使用してテンプレートを定義します。
-
XHTML 用には、ブロックの名前を XData HtmlXslt にします。
-
PDF 用には、ブロックの名前を XData XslFoXslt にします。
次に例を示します。
XData HtmlXslt
{
<xsl:template name="redeven" >
<xsl:param name="num"/>
<xsl:if test="$num mod 2 = 0">
<xsl:attribute name='style'>color:red</xsl:attribute>
</xsl:if>
</xsl:template>
}
XData XslFoXslt
{
<xsl:template name="redeven" >
<xsl:param name="num"/>
<xsl:if test="$num mod 2 = 0">
<xsl:attribute name='color'>red</xsl:attribute>
</xsl:if>
</xsl:template>
}
これらのテンプレートを定義することによって、同じ Zen レポート・クラス内の XData ReportDisplay ブロックに、以下のような <item> を定義することができます。
<item field="@id" width=".7in"
style="border:none;padding-right:4px"
stylecall="redeven" styleparams="@id"
styleparamNames="num" > </item>
以下はその説明です。
-
stylecall 属性には、<xsl:template> の名前を指定しています。
-
styleparamNames 属性には、<xsl:template> で指定した <xsl:param> の名前を指定しています。その他の名前を指定するには、セミコロンで区切ります。
-
styleparams 属性には、そのパラメータに割り当てる値を指定する式を指定しています。styleparams 式には、リテラル値、ノード・セット、XPath 式、または XSLT 関数呼び出しを使用できます。XSLT の <xsl:with-param> の値として有効な値であれば、styleparams にも使用できます。複数の式を指定するには、セミコロンで区切ります。styleparamNames と styleparams の数は必ず一致しなければなりません。
結果として、偶数の ID を持つエントリは赤色になります。これらの属性の詳細は、“レポートの表示属性” セクションにある属性のテーブルを参照してください。
項目のレンダリング時の XSLT テンプレートの呼び出し
このセクションで説明する機能は、<item> 要素にのみ適用されます。
XSLT テンプレートを定義するには、Zen レポート・クラスの AllXslt、HtmlXslt、または XslFoXslt という XData ブロックにそのテンプレートを記述します。以下に例を示します。
XData AllXslt
{
<xsl:template name="sum">
<!-- Initialize nodes to empty node set -->
<xsl:param name="nodes"/>
<xsl:param name="result" select="0"/>
<xsl:choose>
<xsl:when test="not($nodes)">
<xsl:value-of select="$result"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="value" select="$nodes[1]"/>
<!-- recursively sum the rest of the nodes -->
<xsl:call-template name="sum">
<xsl:with-param name="nodes" select="$nodes[position( ) != 1]"/>
<xsl:with-param name="result" select="$result + $value"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
}
このテンプレートを定義することによって、同じ Zen レポート・クラス内の XData ReportDisplay ブロックに、以下のような <item> を定義することができます。
<item call="sum" params="Sale/@amount" paramNames="nodes">
<caption value="Total Sales"/>
</item>
以下はその説明です。
-
call 属性には、<xsl:template> の名前を指定しています。
-
paramNames 属性には、<xsl:template> で指定した <xsl:param> の名前を指定しています。その他の名前を指定するには、セミコロンで区切ります。
-
params 属性には、そのパラメータに割り当てる値を指定する式を指定しています。params 式には、リテラル値、ノード・セット、XPath 式、または XSLT 関数呼び出しを使用できます。XSLT の <xsl:with-param> の値として有効な値であれば、params にも使用できます。複数の式を指定するには、セミコロンで区切ります。paramNames と params の数は必ず一致しなければなりません。
call を使用して <item> の値を取得する場合、<item> 文の中で formatNumber 属性を使用して結果をフォーマットすることはできません。代わりに、call 属性で参照している <xsl:template> の中で XSLT の format-number 関数を使用します。以下の XData AllXslt ブロックの例では、この規則を示しています。
XData AllXslt
{
<xsl:template name="mypct">
<xsl:param name="num"/>
<xsl:param name="denom"/>
<xsl:variable name="v1" select="$num[1]"/>
<xsl:variable name="v2" select="$denom[1]"/>
<xsl:choose>
<xsl:when test="$v2 != 0">
<xsl:value-of
select="format-number(round(($v1 div $v2)*10000) div 10000,'##,###.00%')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number(0,'##,###.00%')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
}
call、paramNames、および params の各プロパティは、<item> 要素でのみサポートされています。これらの属性の詳細は、“<item>” セクションにある属性のテーブルを参照してください。
Zen レポートのメソッドの条件付き実行
“Zen レポートのチュートリアル” の説明にあるように、Zen レポート・クラスは CSP ページでもあります。つまり、通常の CSP ページと同様、実行時の Zen レポートのロジックの中には、サーバで実行される部分もあればブラウザで実行される部分もあります。
既定の Zen レポート・クラスでは、サーバで XSLT を処理して XHTML 出力を生成し、その結果をブラウザに送信して表示します。この動作は、XSLTMODE パラメータで制御されます。また、このパラメータは既定で "server" に設定されます。必要に応じて、XSLTMODE を "browser" に設定できますが、出力フォーマットが PDF の場合は、XSLTMODE の設定にかかわらず、サーバ側で処理が行われます。
出力フォーマットが XHTML で、XSLTMODE を "browser" に設定している場合、Zen レポートの CSP インスタンスはブラウザと 2 回通信します。1 回目で XML を生成し、2 回目で XSLT を生成します。その結果、Zen レポートを表示するたびに、以下の説明に適合するメソッドが 2 回自動的に呼び出されます。
-
Zen レポート・クラスにカスタム・コードを持つコールバック・メソッド (%OnPreHTTP() や %OnAfterReport() など)。
-
クラスのあらゆるプロパティの InitialExpression によって呼び出されたメソッド。
XSLTMODE を "browser" に設定している場合に、不要なパフォーマンス・コストが発生しないようにするには、Zen レポートの現在の表示モードに基づいて条件付きで一部のみを実行するように、これらのメソッドをプログラムします。以下の例では、コールバック・メソッド %OnAfterReport() でこのような方法をとっています。この例では、現在の表示モードを確認するために、次のようにさまざまな規約を使用します。
-
ObjectScript 関数の $ZCONVERT ($ZCVT) でオプション "L" を指定すると、指定した文字列の文字がすべて小文字に変換されます。
-
ObjectScript 関数の $GET ($G) を使用すると、指定した変数のデータ値、または値が設定されていない場合にはその変数の既定値が返されます。
-
%request.Data 構文を使用すると、CSP ページの呼び出しで指定した URL 文字列から、$MODE パラメータの値が取得されます。"Caché Server Pages (CSP) の使用法" の “%CSP.Request オブジェクト” を参照してください。
-
$$$GETPARAMETER("DEFAULTMODE") マクロにより、Zen レポートの DEFAULTMODE パラメータの値が検索されます。そこで DEFAULTMODE が未定義の場合は、このマクロによりアプリケーション・クラスの値が検索されます。アプリケーション・クラスは、APPLICATION パラメータで指定するか、もしくは %ZEN.Report.defaultApplicationOpens in a new tab であるかのいずれかとなります。
Method %OnAfterReport() As %Status
{
if $IsObject($G(%request))
{
set tMode = $ZCVT($G(%request.Data("$MODE",1),$$$GETPARAMETER("DEFAULTMODE")),"L")
if (tMode="tohtml")
{
; Place the callback logic for XSLT generation here
}
elseif (tMode="html")
{
; Place the callback logic for XHTML generation here
}
}
else
{
; Place the callback logic for call from command line here
}
Quit $$$OK
}
以下の例では、メソッドの呼び出しによって設定される InitialExpression を含むプロパティを示しています。
Property testProp As %String [ InitialExpression = {..initExpr()} ];
メソッド自体は次のように定義できます。
Method initExpr() As %String
{
if $IsObject($G(%request))
{
Set tMode = $ZCVT($G(%request.Data("$MODE",1), $$$GETPARAMETER("DEFAULTMODE") ),"L")
if (tMode="xml")
{
set initVal="mode is xml"
}
elseif (tMode="tohtml")
{
set initVal="mode is toHtml"
}
elseif (tMode="html")
{
set initVal="mode is html"
}
else
{
set initVal="all other modes, for completeness"
}
}
else
{
Set initVal="called from command line, no potential second round-trip."
}
Quit initVal
}
レポート生成前後のコードの実行
Zen レポートは、%ZEN.Report.reportPageOpens in a new tab の拡張クラスです。このベース・クラスには、ユーザ独自の Zen レポート・クラスでオーバーライドできるコールバック・メソッドが用意されています。これらのコールバック・メソッドを使用すると、さまざまな処理の前後に Zen で実行する文を追加できます。この処理としては、最初の HTTP 要求の受信、XML データ・ソースの生成、XSLT スタイルシートの記述、レポート表示の作成、要求したフォーマットでのレポート出力などがあります。
以下のテーブルの説明にあるように、Zen レポートのコールバック・メソッドは自動的に実行されます。
メソッド | 実行のタイミング | 目的 | 返り値 |
---|---|---|---|
%OnPreHTTP() | Zen レポートで最初の HTTP 要求を受信した後で、%OnBeforeReport() を実行する前。 | 最初の HTTP 要求のデータに基づいて文を実行します。%OnPreHTTP() メソッドで 0 (False) が返された場合、レポートの実行は直ちに停止します。 | %Status |
%OnBeforeReport() | %OnPreHTTP() を実行した後で、Zen の主要な処理シーケンス (XML データ・ソースの生成、XSLT スタイルシートの記述、およびレポート表示の作成) が始まる前。 | 主要な処理シーケンスの前に入力を調整します。 | %Status |
OnAfterCreateDisplay() | 主要な処理シーケンスの最終段階で、レポートの表示オブジェクトを作成した後、要求されたフォーマットでその表示オブジェクトを出力する前。 |
出力前に表示コンテンツを調整します。個別の項目にアクセスするには、%GetComponentByID(id) で id 属性を指定します。使用例は、“Zen レポートのページのフォーマット” の章の “id 属性” を参照してください。 |
— |
%OnAfterReport() | Zen ですべてのレポート処理が完了し、要求されたフォーマットで表示を出力した後。 | 主要な処理シーケンスの終了後にクリーンアップを実行します。 | %Status |