どちらの例でも、簡易化のために、XML ドキュメント内のノードには、そのクラスのエクステント内の ID と比較できる ID が含まれていると想定しています。当然ながら、他の方法で XML ドキュメントを既存のオブジェクトと比較することもできます。
例 1 : XML 対応クラス内の XMLNew() の変更
まず、以下の XML ファイルについて考えてみましょう。
<?xml version="1.0" encoding="UTF-8"?>
<root>
<Person>
<IRISID>4</IRISID>
<Name>Quine,Maria K.</Name>
<DOB>1964-11-14</DOB>
<Address>
<City>Hialeah</City>
<Zip>94999</Zip>
</Address>
<Doctors>
<Doctor>
<Name>Vanzetti,Debra B.</Name>
</Doctor>
</Doctors>
</Person>
...
このファイルは、次の InterSystems IRIS クラスにマッピングします (一部のみ表示)。
Class GXML.PersonWithXMLNew Extends (%Persistent,%Populate,%XML.Adaptor)
{
Parameter XMLNAME="Person";
/// make sure this is the same as the XMLNAME of the property
/// in this class that is of type %XML.Id
Parameter NAMEOFEXPORTID As %String = "IRISID";
Property IdForExport
As %XML.Id(XMLNAME="IRISID",XMLPROJECTION="ELEMENT") [Private,Transient];
Property Name As %Name;
Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h");
Property Address As GXML.Address;
Property Doctors As list Of GXML.Doctor;
}
このクラスでは、IdForExport プロパティの目的は、このクラスのオブジェクトがエクスポートされるときに InterSystems IRIS 内部 ID を要素 (IRISID) に投影することです (この例では、これによりインポート用の適切なファイルを簡単に生成できます。お使いのクラスにはこのようなプロパティが含まれている必要はありません)。
NAMEOFEXPORTID パラメータを使用して、このクラスのオブジェクトをエクスポートする際に InterSystems IRIS ID 用に使用する要素を指定します。これが含まれている理由は、このクラスに追加したカスタマイズされた XMLNew() メソッドの利便性のためだけです。このメソッドの定義は以下のとおりです。
ClassMethod XMLNew(doc As %XML.Document, node As %Integer,
contOref As %RegisteredObject = "") As GXML.PersonWithXMLNew
{
Set id=""
Set tmpnode=doc.GetNode(node)
Do tmpnode.MoveToFirstChild()
Do {
//compare data node to the string given by the NAMEOFEXPORTID parameter
//which indicates the XMLNAME of the ids for this object
If tmpnode.NodeData=..#NAMEOFEXPORTID {
//get the text from this node; this corresponds to an id in the database
Do tmpnode.GetText(.id)}
} While tmpnode.MoveToNextSibling()
//if there is no id in the given node, create a new object
If id="" {
Write !, "Creating a new object..."
Quit ..%New()}
//open the given object
Set result=..%OpenId(id)
//if the id doesn't correspond to an existing object, create a new object
If result=$$$NULLOREF {
Write !, "Creating a new object..."
Quit ..%New()}
Write !, "Updating an existing object..."
Quit result
}
%XML.ReaderOpens in a new tab は、XML ドキュメントを読み取ってノードを GXML.PersonWithXMLNew と相互に関連付ける際に、このメソッドを呼び出します。このメソッドは、このクラス内の NAMEOFEXPORTID パラメータの値 (IRISID) を参照します。次にこのメソッドは、IRISID という要素を持つドキュメント内のノードを調べて、その値を取得します。
この ID がこのクラスの既存オブジェクトに対応している場合は、このメソッドはそのインスタンスを開きます。そうでない場合は、このメソッドはこのクラスの新しいインスタンスを開きます。どちらの場合でも、開かれたインスタンスは XML ドキュメントで指定されたプロパティを受け取ります。
最後に、次のユーティリティ・クラスには、XML ファイルを開いて %XML.ReaderOpens in a new tab を呼び出すメソッドが含まれています。
Class GXML.DemoXMLNew Extends %RegisteredObject
{
ClassMethod ReadFile(filename As %String = "c:\temp\sample.xml")
{
Set reader=##class(%XML.Reader).%New()
Set sc=reader.OpenFile(filename)
If $$$ISERR(sc) {Do $system.OBJ.DisplayError(sc) Quit }
Do reader.Correlate("Person","GXML.PersonWithXMLNew")
//loop through elements in file
While reader.Next(.person,.sc) {
Write !,person.Name,!
Set sc=person.%Save()
If $$$ISERR(sc) {Do $system.OBJ.DisplayError(sc) Quit }
}
Quit
}
}
上記のメソッドを実行すると、ファイル内の <Person> 要素ごとに以下のいずれかの操作が実行されます。
以下はその例です。
GXML>d ##class(GXML.DemoXMLNew).ReadFile()
Updating an existing object...
Zampitello,Howard I.
Creating a new object...
Smyth,Linda D.
Creating a new object...
Vanzetti,Howard I.
例 2 : カスタム XML アダプタ内の XMLNew() の変更
2 つ目の例では、1 つ目の例と同じ操作を実行するカスタム XML アダプタを作成します。このアダプタ・クラスは以下のとおりです。
Class GXML.AdaptorWithXMLNew Extends %XML.Adaptor
{
/// make sure this is the same as the XMLNAME of the property in this class
/// that is of type %XML.Id
Parameter NAMEOFEXPORTID As %String = "IRISID";
Property IdForExport
As %XML.Id(XMLNAME="IRISID",XMLPROJECTION="ELEMENT") [Private,Transient];
ClassMethod XMLNew(document As %XML.Document, node As %Integer,
containerOref As %RegisteredObject = "") As %RegisteredObject
[CodeMode=objectgenerator,GenerateAfter=%XMLGenerate,ServerOnly=1]
{
If %compiledclass.Name'="GXML.AdaptorWithXMLNew" {
Do %code.WriteLine(" Set id=""""")
Do %code.WriteLine(" Set tmpnode=document.GetNode(node)")
Do %code.WriteLine(" Do tmpnode.MoveToFirstChild()")
Do %code.WriteLine(" Do {")
Do %code.WriteLine(" If tmpnode.NodeData=..#NAMEOFEXPORTID ")
Do %code.WriteLine(" {Do tmpnode.GetText(.id)}")
Do %code.WriteLine(" } While tmpnode.MoveToNextSibling() ")
Do %code.WriteLine(" If id="""" {")
Do %code.WriteLine(" Write !,""Creating new object...""")
Do %code.WriteLine(" Quit ##class("_%class.Name_").%New()}")
Do %code.WriteLine(" set result=##class("_%class.Name_").%OpenId(id)")
Do %code.WriteLine(" If result=$$$NULLOREF {")
Do %code.WriteLine(" Write !,""Creating new object...""")
Do %code.WriteLine(" Quit ##class("_%class.Name_").%New() }")
Do %code.WriteLine(" Write !,""Updating existing object ...""")
Do %code.WriteLine(" Quit result")
}
QUIT $$$OK
}
}
IdForExport プロパティと NAMEOFEXPORTID パラメータによって、サブクラスのオブジェクトがエクスポートされるときに InterSystems IRIS 内部 ID を要素に投影する方法の規約が決定されます。その趣旨は、サブクラス内の IdForExport を再定義する場合は、それに応じて NAMEOFEXPORTID を再定義するというものです。
このクラスでは、XMLNew() メソッドはメソッド・ジェネレータです。このクラス (または任意のサブクラス) がコンパイルされると、InterSystems IRIS はここで示しているコードをこのメソッドの本体に書き込みます。"クラスの定義と使用" の "メソッド・ジェネレータ" を参照してください。
以下のクラスは、カスタム・アダプタを拡張します。
Class GXML.PersonWithXMLNew2
Extends (%Persistent, %Populate, GXML.AdaptorWithXMLNew)
{
Parameter XMLNAME = "Person";
Property Name As %Name;
Property DOB As %Date(FORMAT = 5, MAXVAL = "+$h");
Property Address As GXML.Address;
Property Doctors As list Of GXML.Doctor;
}
前出のサンプル ReadFile メソッドを実行すると、ファイル内の <Person> 要素ごとに、このメソッドは新しいレコードを作成して保存するか、既存のレコードを開いて更新します。