この章の内容は次のとおりです。
関連項目: 『Oracle XML DB開発者ガイド』 |
Simple Object Access Protocol(SOAP)は、HTTPおよびHTTPSにより分散環境のピア間の構造化情報や入力情報を送受信するためのXMLプロトコルです。XDK for 10gリリース2でサポートされるのはHTTP 1.0のみです。SOAPは次の3つの部分に分かれています。
メッセージ内容の表示方法、メッセージの処理者、処理の任意または必須を定義するSOAPエンベロープ
アプリケーションのデータ型をXMLへ、またXMLをアプリケーションのデータ型へ変換するためのシリアライズおよびデシリアライズ・ルール
コールとレスポンスを定義するSOAPリモート・プロシージャ・コール(RPC)
注意: RPCとシリアライズおよびデシリアライズはこのリリースではサポートされません。 |
SOAPはXMLを使用するため、オペレーティング・システムや言語に依存しません。この章では、SOAPメッセージの読取りや書込みを行う関数のC実装について説明します。
SOAPバージョン1.2は、メッセージ内容を説明するXML Information Set(抽象データセット、XML 1.0も使用可)として指定されるXMLベースのメッセージ定義です。バージョン1.1もサポートされています。
Simple Object Access Protocol(SOAP)は、リクエストおよびレスポンスをインターネット経由で送受信するための軽量プロトコルです。このプロトコルはXMLおよび転送プロトコル(HTTPなど)に基づくもので、多くの場合、ファイアウォールによってブロックされません。SOAPはオペレーティング・システム、実装言語およびオブジェクト・モデルに依存しません。
SOAPの長所は、異種ソフトウェア・コンポーネント間の連結機能にあります。たとえば、Visual BasicクライアントからUNIXコンピュータ上で動作するCORBAサービスを起動したり、MacintoshクライアントからLinux上で動作するPerlオブジェクトを起動したりできます。
SOAPメッセージは次の部分に分かれています。
エンベロープ: メッセージを含み、その処理方法、処理者、およびその処理がオプションか必須かを指定します。Envelope
要素は必須です。
エンコーディング規則: アプリケーションで使用するデータ型を記述します。これらの規則では、アプリケーションのデータ型をXMLへ、またXMLをデータ型へ変換するシリアライズ・メカニズムが定義されます。
リモート・プロシージャ・コール(RPC): リクエストおよびレスポンスの規則を定義します。この必須要素は本体要素と呼ばれます。Body
要素には、メソッド名を名前とする最初のサブ要素を指定します。このメソッド・リクエスト要素には、各入出力パラメータの要素が含まれます。要素名はパラメータ名です。RPCはこのリリースではサポートされていません。
SOAPは転送プロトコルに依存しません。ただし、HTTPによるリモート・サービスの起動に使用されるSOAPが、プログラミングされたコンテンツをインターネット上で提供するための標準として扱われています。
SOAPは、転送プロトコルに依存しないだけでなく、オペレーティング・システムにも依存しません。そのため、プログラムが異なる言語で記述されている場合や、異なるオペレーティング・システム上で実行される場合にも通信が可能です。
SOAPのメッセージには次の種類があります。
サービスのリクエスト(入力パラメータを含む)
リクエストされたサービスからのレスポンス(戻り値および出力パラメータを含む)
エラー・コードおよびエラー情報を含むオプションのFault要素
SOAPのメッセージでは、ペイロードにXML用にエンコードされたデータが含まれます。処理情報は含まれません。メッセージ・ヘッダーには処理情報が含まれる場合があります。
SOAPリクエストでは、XMLペイロードに次のような要素が含まれます。
ルート要素
メソッド要素
ヘッダー要素(オプション)
例22-1に、サンプルSOAPメッセージ・リクエストの書式を示します。GetLastTradePrice
SOAPリクエストをStockQuote
サービスに送信します。このリクエストは企業の銘柄記号を示す文字列パラメータを取り、SOAPレスポンスで株価を示すfloat型を戻します。
例22-1 SOAPリクエスト・メッセージ
POST /StockQuote HTTP/1.0 Host: www.stockquoteserver.com Content-Type: application/soap+xml; charset="utf-8" Content-Length: nnnn SOAPAction: "Some-URI" <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" SOAP-ENV:encodingStyle="http://www.w3.org/2003/05/soap-encoding/"> <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m="Some-URI"> <symbol>ORCL</symbol> <m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
例22-1のXML文書はSOAPメッセージです。<SOAP-ENV:Envelope>
要素は、XML文書の最上位要素です。ペイロードはメソッド要素<m:GetLastTradePrice>
で示されます。XML名前空間を使用して、SOAP識別子とアプリケーション固有の識別子を区別します。
ヘッダーの最初の行では、リクエストの転送プロトコルにHTTPを使用することが指定されています。
POST /StockQuote HTTP/1.1
SOAPは転送プロトコルに依存しないため、XMLペイロード形式を決定する規則は、このペイロードがHTTPで転送されるということには関係ありません。このHTTPリクエストはURI /StockQuote
を指しています。SOAP仕様ではコンポーネントのアクティブ化の問題を処理しないため、このURIでコンポーネントのアクティブ化方法とGetLastTradePrice
メソッドの起動方法を指定します。
例22-2に、例22-1のリクエストに対するレスポンスの書式を示します。<Price>
要素には、最初のメッセージでリクエストされたORCL
の株価が含まれています。
例22-2 SOAPレスポンス・メッセージ
HTTP/1.0 200 OK Content-Type: application/soap+xml; charset="utf-8" Content-Length: nnnn <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" SOAP-ENV:encodingStyle="http://www.w3.org/2003/05/soap-encoding/"> <SOAP-ENV:Body> <m:GetLastTradePriceResponse xmlns:m="Some-URI"> <Price>13.5</Price> </m:GetLastTradePriceResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
例22-1および例22-2のメッセージは、双方向のSOAPメッセージ(SOAPリクエストがSOAPレスポンスで応答される)を示しています。一方向のSOAPメッセージにはSOAPレスポンス・メッセージは不要です。
SOAPクライアントはXML文書を生成するユーザー作成アプリケーションです。生成されたXML文書でSOAPサービスへのリクエストを行い、SOAPレスポンスを処理します。XDKのSOAP実装は、有効なSOAPリクエストを送信するすべてのクライアントからのリクエストを処理します。
SOAPクライアントAPIの便利な機能を次に示します。
リクエストおよびレスポンス用の同期式起動モデルをサポートします。
SOAPリクエストを行うクライアント・アプリケーションの作成を簡素化します。
SOAPリクエストの作成および基礎となる転送プロトコルを使用したリクエスト送信の詳細をカプセル化します。
交換可能な転送をサポートし、クライアントは転送を簡単に変更できます(HTTPおよびHTTPSによる転送が可能ですが、このリリースでサポートされるのはHTTP 1.0のみです)。
SOAPクライアントでリクエストの送信やレスポンスの受信を行うには、次の手順を実行する必要があります。
サービスの起動にすべての必要なパラメータを収集します。
SOAPプロトコルに従って作成されるXMLメッセージである、SOAPサービスのリクエスト・メッセージを作成します。これは、XMLでエンコードされたすべての入力パラメータのすべての値を含みます。このプロセスをシリアライズといいます。
SOAPサーバーがサポートする転送プロトコルを使用してリクエストをSOAPサーバーに送信します。
SOAPレスポンス・メッセージを受信します。
SOAP Fault要素を処理して、リクエストの成否を判断します。
XMLから戻されたパラメータをネイティブなデータ型に変換します。このプロセスをデシリアライズといいます。
必要に応じて結果を使用します。
SOAP Cの実装では、xml.hヘッダーが使用されます。SOAPコンテキストを作成する前に、xmlctx
タイプのコンテキストを作成する必要があります。
SOAPのHTTP要素はユーザーからは見えません。SOAPエンドポイントは、組合せ(バインディング、エンドポイント)で指定されます。ここで、バインディングはxmlsoapbind
タイプ、バインディングに応じたエンドポイントは(void *
)です。現在サポートされているバインディングはXMLSOAP_BIND_HTTP
のみです。HTTPバインディングの場合、エンドポイントは(OraText *
) URLです。
SOAPレイヤーでエンドポイント間のSOAPメッセージが作成および転送され、受信したSOAPメッセージが分解されます。
C関数はxmlsoap.h
で宣言します。次に、ヘッダー・ファイルの開始部分を示します。
例22-3 xmlsoap.hに定義されたSOAP C関数
FILE NAME xmlsoap.h - XML SOAP APIs FILE DESCRIPTION XML SOAP Public APIs PUBLIC FUNCTIONS XmlSoapCreateCtx - Create and return a SOAP context XmlSoapDestroyCtx - Destroy a SOAP context XmlSoapCreateConnection - Create a SOAP connection object XmlSoapDestroyConnection - Destroy a SOAP connection object XmlSoapCall - Send a SOAP message & wait for reply XmlSoapCreateMsg - Create and return an empty SOAP message XmlSoapDestroyMsg - Destroy a SOAP message created w/XmlSoapCreateMsg XmlSoapGetEnvelope - Return a SOAP message's envelope XmlSoapGetHeader - Return a SOAP message's envelope header XmlSoapGetBody - Return a SOAP message's envelope body XmlSoapAddHeaderElement - Adds an element to a SOAP header XmlSoapGetHeaderElement - Gets an element from a SOAP header XmlSoapAddBodyElement - Adds an element to a SOAP message body XmlSoapGetBodyElement - Gets an element from a SOAP message body XmlSoapSetMustUnderstand - Set mustUnderstand attr for SOAP hdr elem XmlSoapGetMustUnderstand - Get mustUnderstand attr from SOAP hdr elem XmlSoapSetRole - Set role for SOAP header element XmlSoapGetRole - Get role from SOAP header element XmlSoapSetRelay - Set relay Header element property XmlSoapGetRelay - Get relay Header element property XmlSoapSetFault - Set Fault in SOAP message XmlSoapHasFault - Does SOAP message have a Fault? XmlSoapGetFault - Return Fault code, reason, and details XmlSoapAddFaultReason - Add additional Reason to Fault XmlSoapAddFaultSubDetail - Add additional child to Fault Detail XmlSoapGetReasonNum - Get number of Reasons in Fault element XmlSoapGetReasonLang - Get a lang of a reasons with a particular iindex. XmlSoapError - Get error message(s) */ #ifndef XMLSOAP_ORACLE # define XMLSOAP_ORACLE # ifndef XML_ORACLE # include <xml.h> # endif /*--------------------------------------------------------------------------- Package SOAP - Simple Object Access Protocol APIs W3C: "SOAP is a lightweight protocol for exchange of information in a decentralized, distributed environment. It is an XML based protocol that consists of three parts: an envelope that defines a framework for describing what is in a message and how to process it, a set of encoding rules for expressing instances of application-defined datatypes, and a convention for representing remote procedure calls and responses." Atachments are only allowed in Soap 1.1 In Soap 1.2 body may not have other elements if Fault is present. Structure of a SOAP message: [SOAP message (XML document) [SOAP envelope [SOAP header? element* ] [SOAP body (element* | Fault)? ] ] ] ---------------------------------------------------------------------------*/ ...
関連項目: C SOAP APIについては、『Oracle Database XML C APIリファレンス』を参照してください。 |
次に、旅行会社にJohn Smithのニューヨーク発ロサンゼルス行きの航空券を予約するリクエストを記述したXML文書の例を示します。
例22-4 例1 SOAPメッセージ
<?xml version='1.0' ?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"> <env:Header> <m:reservation xmlns:m="http://travelcompany.example.org/reservation" env:role="http://www.w3.org/2003/05/soap-envelope/role/next" env:mustUnderstand="true"> <m:reference>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:reference> <m:dateAndTime>2001-11-29T13:20:00.000-05:00</m:dateAndTime> </m:reservation> <n:passenger xmlns:n="http://mycompany.example.com/employees" env:role="http://www.w3.org/2003/05/soap-envelope/role/next" env:mustUnderstand="true"> <n:name>John Smith</n:name> </n:passenger> </env:Header> <env:Body> <p:itinerary xmlns:p="http://travelcompany.example.org/reservation/travel"> <p:departure> <p:departing>New York</p:departing> <p:arriving>Los Angeles</p:arriving> <p:departureDate>2001-12-14</p:departureDate> <p:departureTime>late afternoon</p:departureTime> <p:seatPreference>aisle</p:seatPreference> </p:departure> <p:return> <p:departing>Los Angeles</p:departing> <p:arriving>New York</p:arriving> <p:departureDate>2001-12-20</p:departureDate> <p:departureTime>mid-morning</p:departureTime> <p:seatPreference/> </p:return> </p:itinerary> <q:lodging xmlns:q="http://travelcompany.example.org/reservation/hotels"> <q:preference>none</q:preference> </q:lodging> </env:Body> </env:Envelope>
この例では、XML文書の作成、送信、リプライの受信、分解が簡素化されています。最小限のエラー・チェックが行われます。エラーを修正するDEBUG
オプションが示されています。このプログラムは、すべてのオペレーティング・システムで動作するとはかぎりません。このXML文書を送信するには、クライアントのCプログラムで次の手順を実行します。
main()
で変数を宣言した後、XMLコンテキスト、xctx
をXmlCreate()
で作成し、このコンテキストを使用してSOAPコンテキスト、ctx
をXmlSoapCreateCtx()
で作成します。
メッセージを作成するためにXmlSoapCreateMsg()
をコールすると、空のSOAPメッセージが戻されます。
ヘッダーをXmlSoapAddHeaderElement()
、XmlSoapSetRole()
、XmlSoapSetMustUnderstand()
およびXmlDomAddTextElem()
で作成して、エンベロープにテキストを指定します。
本体要素をXmlSoapAddBodyElement()
とXmlDomCreateElemNS()
で作成し、XmlDomAddTextElem()
をコールします。次に、XmlDomAppendChild()
を追加すれば、ニューヨーク発ロサンゼルス行きの便を指定する本体のセクションが完成します。
帰りの航空券についても同様の方法で作成します。宿泊先を新たなXmlSoapAddBodyElement()
コールで追加します。
次に、XmlSoapCreateConnection()
で接続を作成し、HTTPバインディング(現時点で使用可能な唯一のバインディング)とエンドポイントのURLを指定する必要があります。
XmlSoapCall()
関数で、SOAPサーバーを使用して定義済の接続でメッセージを送信し、リプライを待機します。
メッセージ・リプライは別のSOAPメッセージの形式で戻されます。それには、XmlSaveDom()
とXmlSoapHasFault()
をXmlSoapGetFault()
とともに使用して、フォルトをチェックし、分析します。フォルトを解析して各部分に分けます。その出力結果がこの例です。
フォルトが戻されなければ、次のXmlSoapGetBody()
でエンベロープの本体が戻されます。XmlSaveDom()
を実行すると、戻されたメッセージの分析が完了します。
クリーンアップするには、メッセージとリプライのそれぞれに対してXmlSoapDestroyMsg()
を実行し、XmlDestroyCtx()
でSOAPコンテキストを削除し、XmlDestroy()
でXMLコンテキストを削除します。
例1のCクライアント・プログラムを次に示します。
例22-5 例1 SOAP Cクライアント
#ifndef S_ORACLE # include <s.h> #endif #ifndef XML_ORACLE # include <xml.h> #endif #ifndef XMLSOAP_ORACLE # include <xmlsoap.h> #endif #define MY_URL "http://my_url.com" /* static function declaration */ static xmlerr add_ns_decl(xmlsoapctx *ctx, xmlctx *xctx, xmlelemnode *elem, oratext *pfx, oratext *uri); sb4 main( sword argc, char *argv[]) { xmlctx *xctx; xmlerr xerr; xmlsoapctx *ctx; oratext *url; xmlsoapcon *con; xmldocnode *msg1, *reply, *msg2, *msg3; xmlelemnode *res, *pas, *pref, *itin, *departure, *ret, *lodging; xmlelemnode *departing, *arriving, *trans, *text, *charge, *card, *name; xmlelemnode *body, *header; boolean has_fault; oratext *code, *reason, *lang, *node, *role; xmlelemnode *detail; oratext *comp_uri = "http://travelcompany.example.org/"; oratext *mres_uri = "http://travelcompany.example.org/reservation"; oratext *trav_uri = "http://travelcompany.example.org/reservation/travel"; oratext *hotel_uri = "http://travelcompany.example.org/reservation/hotels"; oratext *npas_uri = "http://mycompany.example.com/employees"; oratext *tparty_uri = "http://thirdparty.example.org/transaction"; oratext *estyle_uri = "http://example.com/encoding"; oratext *soap_style_uri = "http://www.w3.org/2003/05/soap-encoding"; oratext *estyle = "env:encodingStyle"; oratext *finance_uri = "http://mycompany.example.com/financial"; if (!(xctx = XmlCreate(&xerr, (oratext *)"SOAP_test",NULL))) { printf("Failed to create XML context, error %u\n", (unsigned) xerr); return EX_FAIL; } /* Create SOAP context */ if (!(ctx = XmlSoapCreateCtx(xctx, &xerr, (oratext *) "example", NULL))) { printf("Failed to create SOAP context, error %u\n", (unsigned) xerr); return EX_FAIL; } /* EXAMPLE 1 */ /* construct message */ if (!(msg1 = XmlSoapCreateMsg(ctx, &xerr))) { printf("Failed to create SOAP message, error %u\n", (unsigned) xerr); return xerr; } res = XmlSoapAddHeaderElement(ctx, msg1, "m:reservation", mres_uri, &xerr); xerr = XmlSoapSetRole(ctx, res, XMLSOAP_ROLE_NEXT); xerr = XmlSoapSetMustUnderstand(ctx, res, TRUE); (void) XmlDomAddTextElem(xctx, res, mres_uri, "m:reference", "uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d"); (void) XmlDomAddTextElem(xctx, res, mres_uri, "m:dateAndTime", "2001-11-29T13:20:00.000-05:00"); pas = XmlSoapAddHeaderElement(ctx, msg1, "n:passenger", npas_uri, &xerr); xerr = XmlSoapSetRole(ctx, pas, XMLSOAP_ROLE_NEXT); xerr = XmlSoapSetMustUnderstand(ctx, pas, TRUE); (void) XmlDomAddTextElem(xctx, pas, npas_uri, "n:name", "John Smith"); /* Fill body */ /* Itinerary */ itin = XmlSoapAddBodyElement(ctx, msg1, "p:itinerary", trav_uri, &xerr); /* Departure */ departure = XmlDomCreateElemNS(xctx, msg1, trav_uri, "p:departure"); (void) XmlDomAddTextElem(xctx, departure, trav_uri, "p:departing","New York"); (void) XmlDomAddTextElem(xctx, departure, trav_uri, "p:arriving", "Los Angeles"); (void) XmlDomAddTextElem(xctx, departure, trav_uri, "p:departureDate", "2001-12-14"); (void) XmlDomAddTextElem(xctx, departure, trav_uri, "p:departureTime", "late afternoon"); (void) XmlDomAddTextElem(xctx, departure, trav_uri, "p:seatPreference", "aisle"); XmlDomAppendChild(xctx, itin, departure); /* Return */ ret = XmlDomCreateElemNS(xctx, msg1, trav_uri, "p:return"); (void) XmlDomAddTextElem(xctx, ret, trav_uri, "p:departing", "Los Angeles"); (void) XmlDomAddTextElem(xctx, ret, trav_uri, "p:arriving", "New York"); (void) XmlDomAddTextElem(xctx, ret, trav_uri, "p:departureDate", "2001-12-20"); (void) XmlDomAddTextElem(xctx, ret, trav_uri, "p:departureTime", "mid-morning"); pref = XmlDomCreateElemNS(xctx, msg1, trav_uri, "p:seatPreference"); (void) XmlDomAppendChild(xctx, ret, pref); XmlDomAppendChild(xctx, itin, ret); /* Lodging */ lodging = XmlSoapAddBodyElement(ctx, msg1, "q:lodging", hotel_uri, &xerr); (void) XmlDomAddTextElem(xctx, lodging, hotel_uri, "q:preference", "none"); #ifdef DEBUG /* dump the message in debug mode */ printf("Message:\n"); XmlSaveDom(xctx, &xerr, msg1, "stdio", stdout, "indent_step", 1, NULL); #endif /* END OF EXAMPLE 1 */ /* create connection */ url = MY_URL; if (!(con = XmlSoapCreateConnection(ctx, &xerr, XMLSOAP_BIND_HTTP, url, NULL, 0, NULL, 0, "XTest: baz", NULL))) { printf("Failed to create SOAP connection, error %u\n", (unsigned) xerr); return xerr; } reply = XmlSoapCall(ctx, con, msg1, &xerr); XmlSoapDestroyConnection(ctx, con); if (!reply) { printf("Call failed, no message returned.\n"); return xerr; } #ifdef DEBUG printf("Reply:\n"); XmlSaveDom(xctx, &xerr, reply, "stdio", stdout, NULL); #endif printf("\n==== Header:\n "); header = XmlSoapGetHeader(ctx, reply, &xerr); if (!header) { printf("NULL\n"); } else XmlSaveDom(xctx, &xerr, header, "stdio", stdout, NULL); /* check for fault */ has_fault = XmlSoapHasFault(ctx, reply, &xerr); if(has_fault) { lang = NULL; xerr = XmlSoapGetFault(ctx, reply, &code, &reason, &lang, &node, &role, &detail); if (xerr) { printf("error getting Fault %d\n", xerr); return EX_FAIL; } if(code) printf(" Code -- %s\n", code); else printf(" NO Code\n"); if(reason) printf(" Reason -- %s\n", reason); else printf(" NO Reason\n"); if(lang) printf(" Lang -- %s\n", lang); else printf(" NO Lang\n"); if(node) printf(" Node -- %s\n", node); else printf(" NO Node\n"); if(role) printf(" Role -- %s\n", role); else printf(" NO Role\n"); if(detail) { printf(" Detail\n"); XmlSaveDom(xctx, &xerr, detail, "stdio", stdout, NULL); printf("\n"); } else printf(" NO Detail\n"); } else { body = XmlSoapGetBody(ctx, reply, &xerr); printf("==== Body:\n "); if (!body) { printf("NULL\n"); return EX_FAIL; } XmlSaveDom(xctx, &xerr, body, "stdio", stdout, NULL); } (void) XmlSoapDestroyMsg(ctx, reply); (void) XmlSoapDestroyMsg(ctx, msg1); (void) XmlSoapDestroyCtx(ctx); XmlDestroy(xctx); }
旅行会社は、旅行者John Smithがニューヨークのどの空港から出発するかを知る必要があります。選択肢としてJFK(ケネディ空港)、EWR(ニューアーク空港)、LGA(ラガーディア空港)があります。そこで次のリプライが送信されます。
例22-6 例2 SOAPメッセージ
<?xml version='1.0' ?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"> <env:Header> <m:reservation xmlns:m="http://travelcompany.example.org/reservation" env:role="http://www.w3.org/2003/05/soap-envelope/role/next" env:mustUnderstand="true"> <m:reference>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:reference> <m:dateAndTime>2001-11-29T13:35:00.000-05:00</m:dateAndTime> </m:reservation> <n:passenger xmlns:n="http://mycompany.example.com/employees" env:role="http://www.w3.org/2003/05/soap-envelope/role/next" env:mustUnderstand="true"> <n:name>John Smith</n:name> </n:passenger> </env:Header> <env:Body> <p:itineraryClarification xmlns:p="http://travelcompany.example.org/reservation/travel"> <p:departure> <p:departing> <p:airportChoices> JFK LGA EWR </p:airportChoices> </p:departing> </p:departure> <p:return> <p:arriving> <p:airportChoices> JFK LGA EWR </p:airportChoices> </p:arriving> </p:return> </p:itineraryClarification> </env:Body> </env:Envelope>
このXML文書をSOAPメッセージとして送信するには、例22-5「例1 SOAP Cクライアント」の/* EXAMPLE 1 */
から/* END OF EXAMPLE 1 */
までの行を次のコード・ブロックに置き換えます。
例22-7 例2 SOAP Cクライアント
#define XMLSOAP_MAX_NAME 1024 /* we need this function for examples 2 and 3 */ static xmlerr add_ns_decl(xmlsoapctx *ctx, xmlctx *xctx, xmlelemnode *elem, oratext *pfx, oratext *uri) { oratext *aq, aqbuf[XMLSOAP_MAX_NAME]; xmldocnode *doc; oratext *xmlns = "xmlns:"; /* if no room for "xmlns:usersprefix\0" then fail now */ if ((strlen((char *)pfx) + strlen((char *)xmlns)) > sizeof(aqbuf)) return EX_FAIL; (void) strcpy((char *)aqbuf, (char *)xmlns); strcat((char *)aqbuf, (char *)pfx); doc = XmlDomGetOwnerDocument(xctx, elem); aq = XmlDomSaveString(xctx, doc, aqbuf); XmlDomSetAttrNS(xctx, elem, uri, aq, uri); return XMLERR_OK; } /* EXAMPLE 2 */ /* construct message */ if (!(msg2 = XmlSoapCreateMsg(ctx, &xerr))) { printf("Failed to create SOAP message, error %u\n", (unsigned) xerr); return xerr; } res = XmlSoapAddHeaderElement(ctx, msg2, "m:reservation", mres_uri, &xerr); xerr = XmlSoapSetRole(ctx, res, XMLSOAP_ROLE_NEXT); xerr = XmlSoapSetMustUnderstand(ctx, res, TRUE); (void) XmlDomAddTextElem(xctx, res, mres_uri, "m:reference", "uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d"); (void) XmlDomAddTextElem(xctx, res, mres_uri, "m:dateAndTime", "2001-11-29T13:35:00.000-05:00"); pas = XmlSoapAddHeaderElement(ctx, msg2, "n:passenger", npas_uri, &xerr); xerr = XmlSoapSetRole(ctx, pas, XMLSOAP_ROLE_NEXT); xerr = XmlSoapSetMustUnderstand(ctx, pas, TRUE); (void) XmlDomAddTextElem(xctx, pas, npas_uri, "n:name", "John Smith"); /* Fill body */ /* Itinerary */ itin = XmlSoapAddBodyElement(ctx, msg2, "p:itineraryClarification", trav_uri, &xerr); /* Departure */ departure = XmlDomCreateElemNS(xctx, msg2, trav_uri, "p:departure"); departing = XmlDomCreateElem(xctx, msg2, "p:departing"); (void) XmlDomAddTextElem(xctx, departing, trav_uri, "p:airportChoices", "JFK LGA EWR"); (void) XmlDomAppendChild(xctx, departure, departing); XmlDomAppendChild(xctx, itin, departure); /* Return */ ret = XmlDomCreateElemNS(xctx, msg2, trav_uri, "p:return"); arriving = XmlDomCreateElemNS(xctx, msg2, trav_uri, "p:arriving"); (void) XmlDomAddTextElem(xctx, arriving, trav_uri, "p:airportChoices", "JFK LGA EWR"); XmlDomAppendChild(xctx, ret, arriving); XmlDomAppendChild(xctx, itin, ret); #ifdef DEBUG XmlSaveDom(xctx, &xerr, msg2, "stdio", stdout, "indent_step", 1, NULL); #endif
最後のXML文書では、John Smithのクレジット・カード情報をPOSTメソッドで送信します。次の例では、XmlSoapCall()
の実行により、XMLメッセージの前にHTTPヘッダーが記述されています。
例22-8 例3 SOAPメッセージ
POST /Reservations HTTP/1.0 Host: travelcompany.example.org Content-Type: application/soap+xml; charset="utf-8" Content-Length: nnnn <?xml version='1.0' ?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" > <env:Header> <t:transaction xmlns:t="http://thirdparty.example.org/transaction" env:encodingStyle="http://example.com/encoding" env:mustUnderstand="true" >5</t:transaction> </env:Header> <env:Body> <m:chargeReservation env:encodingStyle="http://www.w3.org/2003/05/soap-encoding" xmlns:m="http://travelcompany.example.org/"> <m:reservation xmlns:m="http://travelcompany.example.org/reservation"> <m:code>FT35ZBQ</m:code> </m:reservation> <o:creditCard xmlns:o="http://mycompany.example.com/financial"> <n:name xmlns:n="http://mycompany.example.com/employees"> John Smith </n:name> <o:number>123456789099999</o:number> <o:expiration>2005-02</o:expiration> </o:creditCard> </m:chargeReservation> </env:Body> </env:Envelope>
Cクライアントでは、例22-5「例1 SOAP Cクライアント」の2番目の例と同じ箇所を次のコード・ブロックに置き換えます。
例22-9 例3 SOAP Cクライアント
#define XMLSOAP_MAX_NAME 1024 /* we need this function for examples 2 and 3 */ static xmlerr add_ns_decl(xmlsoapctx *ctx, xmlctx *xctx, xmlelemnode *elem, oratext *pfx, oratext *uri) { oratext *aq, aqbuf[XMLSOAP_MAX_NAME]; xmldocnode *doc; oratext *xmlns = "xmlns:"; /* if no room for "xmlns:usersprefix\0" then fail now */ if ((strlen((char *)pfx) + strlen((char *)xmlns)) > sizeof(aqbuf)) return EX_FAIL; (void) strcpy((char *)aqbuf, (char *)xmlns); strcat((char *)aqbuf, (char *)pfx); doc = XmlDomGetOwnerDocument(xctx, elem); aq = XmlDomSaveString(xctx, doc, aqbuf); XmlDomSetAttrNS(xctx, elem, uri, aq, uri); return XMLERR_OK; } /* EXAMPLE 3 */ if (!(msg3 = XmlSoapCreateMsg(ctx, &xerr))) { printf("Failed to create SOAP message, error %u\n", (unsigned) xerr); return xerr; } trans = XmlSoapAddHeaderElement(ctx,msg3, "t:transaction", tparty_uri, &xerr); xerr = XmlSoapSetMustUnderstand(ctx, trans, TRUE); XmlDomSetAttr(xctx, trans, estyle, estyle_uri); text = XmlDomCreateText(xctx, msg3, "5"); XmlDomAppendChild(xctx, trans, text); /* Fill body */ /* Charge Reservation */ charge = XmlSoapAddBodyElement(ctx,msg3,"m:chargeReservation",comp_uri,&xerr); XmlDomSetAttr(xctx, charge, estyle, soap_style_uri); res = XmlDomCreateElemNS(xctx, msg3, mres_uri, "m:reservation"); if (add_ns_decl(ctx, xctx, res, "m", mres_uri)) return EX_FAIL; (void) XmlDomAddTextElem(xctx, res, mres_uri, "m:code", "FT35ZBQ"); (void) XmlDomAppendChild(xctx, charge, res); /* create card elem with namespace */ card = XmlDomCreateElemNS(xctx, msg3, finance_uri, "o:creditCard"); if (add_ns_decl(ctx, xctx, card, "o", finance_uri)) return EX_FAIL; name = XmlDomAddTextElem(xctx, card, npas_uri, "n:name", "John Smith"); /* add namespace */ if (add_ns_decl(ctx, xctx, name, "n", npas_uri)) return EX_FAIL; (void) XmlDomAddTextElem(xctx, card, finance_uri, "o:number", "123456789099999"); (void) XmlDomAddTextElem(xctx, card, finance_uri, "o:expiration", "2005-02"); (void) XmlDomAppendChild(xctx, charge, card); #ifdef DEBUG XmlSaveDom(xctx, &xerr, msg3, "stdio", stdout, "indent_step", 1, NULL); #endif