XData ブロックの定義と使用
XData ブロックは、コンパイル後のクラスで使用するためにクラス定義に含めるデータの名前とユニットで構成されるクラス・メンバです。
基本
XData ブロックは、クラス定義に含めるデータの名前付きユニットです。通常、クラスのメソッドで使用します。一般的に、これは適格な XML ドキュメントですが、JSON や YAML など、他の形式のデータで構成することもできます。
統合開発環境 (IDE) で直接入力することによって XData ブロックを作成できます。
XData ブロックは、名前付きクラス・メンバ です (プロパティ、メソッドなどと同様)。使用できる XData ブロック・キーワードは以下のとおりです。
-
SchemaSpec — オプションで、XData を検証できる XML スキーマを指定します。
-
XMLNamespace — オプションで、XData ブロックが属する XML ネームスペースを指定します。また、当然ながら、XData ブロック自体の中にもネームスペース宣言を含めることができます。
-
MimeType — XData ブロックのコンテンツの MIME タイプ (正式には、インターネット・メディア・タイプOpens in a new tab)。既定値は text/xml です。
XML の格納に使用する場合、XData ブロックは、1 つのルート XML 要素と任意の有効なコンテンツで構成される必要があります。
XML の例
プログラム的に任意の XData ブロック内の XML ドキュメントにアクセスするには、%Dictionary.CompiledXDataOpens in a new tab および %Dictionary パッケージのその他のクラスを使用します。
少量のシステム・データを定義する場合は、XData ブロックが役に立ちます。例えば、EPI.AllergySeverity クラスに、プロパティ Code (内部使用) と プロパティ Description (ユーザへの表示用) があるとします。このクラスに、次のように XData ブロックを記述できます。
XData LoadData
{
<table>
<row>1^Minor</row>
<row>2^Moderate</row>
<row>3^Life-threatening</row>
<row>9^Inactive</row>
<row>99^Unable to determine</row>
</table>
}
同じクラスに、次のように、この XData ブロックを読み取ってテーブルを生成するクラス・メソッドを記述することもできます。
ClassMethod Setup() As %Status
{
//first kill extent
do ..%KillExtent()
// Get a stream of XML from the XData block contained in this class
Set xdataID="EPI.AllergySeverity||LoadData"
Set compiledXdata=##class(%Dictionary.CompiledXData).%OpenId(xdataID)
Set tStream=compiledXdata.Data
If '$IsObject(tStream) Set tSC=%objlasterror Quit
set status=##class(%XML.TextReader).ParseStream(tStream,.textreader)
//check status
if $$$ISERR(status) do $System.Status.DisplayError(status) quit
//iterate through document, node by node
while textreader.Read()
{
if (textreader.NodeType="chars")
{
set value=textreader.Value
set obj=..%New()
set obj.Code=$Piece(value,"^",1)
set obj.Description=$Piece(value,"^",2)
do obj.%Save()
}
}
}
これから以下の点がわかります。
-
XData に記述する XML は必要最小限で済みます。つまり、独自の要素や属性を持つ XML 要素としてアレルギー反応程度を記述する代わりに、単なるデータの行を区切り文字列として XData ブロックに記述します。これにより、見やすい形式で設定データを記述できます。
-
EPI.AllergySeverity クラスは、XML 対応ではなく、また XML 対応にする必要もありません。
JSON の例
クラスには、次のように JSON コンテンツが含まれる XData ブロックも記述できます。
XData LoadJSONData [MimeType = "application/json"]
{
{
"person":"John",
"age":30,
"car":"Ford"
}
}
同じクラスに、次のように、この XData ブロックを読み取ってダイナミック・オブジェクトを生成するクラス・メソッドを記述することもできます。
/// Reads a JSON XData block
ClassMethod SetupJSON() As %Status
{
// Get a stream of JSON from the XData block contained in this class
Set xdataID="Demo.XData||LoadJSONData"
Set compiledXdata=##class(%Dictionary.CompiledXData).%OpenId(xdataID)
Set tStream=compiledXdata.Data
If '$IsObject(tStream) Set tSC=%objlasterror Quit
// Create a dynamic object from the JSON content and write it as a string
Set dynObject = {}.%FromJSON(tStream)
Write dynObject.%ToJSON()
}
YAML の例
クラスには、以下の Swagger API 仕様のように、YAML コンテンツが含まれる XData ブロックも記述できます。
XData SampleAPI [mimetype = "application/yaml"]
{
swagger: "2.0"
info:
title: Sample API
description: API description in Markdown.
version: 1.0.0
host: api.example.com
basePath: /v1
schemes:
- https
paths:
/users:
get:
summary: Returns a list of users.
description: Optional extended description in Markdown.
produces:
- application/json
responses:
200:
description: OK
}
このクラス・メソッドは XData ブロックを読み取り、そのコンテンツを 1 行ずつ書き込みます。
/// Reads a YAML XData block
ClassMethod SetupYAML() As %Status
{
// Get a stream of YAML from the XData block contained in this class
Set xdataID="Demo.XData||SampleAPI"
Set compiledXdata=##class(%Dictionary.CompiledXData).%OpenId(xdataID)
Set tStream=compiledXdata.Data
If '$IsObject(tStream) Set tSC=%objlasterror Quit
// Write the content from the stream, line by line
While 'tStream.AtEnd {
Write tStream.ReadLine(,.sc,.eol)
If eol { Write ! }
}
}