ヘッダーをスキップ
Oracle® XML Developer's Kitプログラマーズ・ガイド
11gリリース2 (11.2)
B56264-06
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

22 C XDKでのSOAPの使用

この章の内容は次のとおりです。


関連項目:

『Oracle XML DB開発者ガイド』

SOAP for Cの概要

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もサポートされています。


関連項目:

W3C SOAP 1.2仕様については、次を参照してください。

SOAPメッセージの概要

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を使用すると、プログラムが異なる言語で記述されている場合や、異なるオペレーティング・システム上で実行される場合にも通信が可能です。

SOAPメッセージの書式

SOAPのメッセージには次の種類があります。

  • サービスのリクエスト(入力パラメータを含む)

  • リクエストされたサービスからのレスポンス(戻り値および出力パラメータを含む)

  • エラー・コードおよびエラー情報を含むオプションのFault要素

SOAPのメッセージでは、ペイロードにXML用にエンコードされたデータが含まれます。処理情報は含まれません。メッセージ・ヘッダーには処理情報が含まれる場合があります。

SOAPリクエスト

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メソッドの起動方法を指定します。

SOAPレスポンスの例

例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クライアントの使用

SOAPクライアントはXML文書を生成するユーザー作成アプリケーションです。生成されたXML文書でSOAPサービスへのリクエストを行い、SOAPレスポンスを処理します。XDKのSOAP実装は、有効なSOAPリクエストを送信するすべてのクライアントからのリクエストを処理します。

SOAPクライアントAPIの便利な機能を次に示します。

  • リクエストおよびレスポンス用の同期式起動モデルをサポートします。

  • SOAPリクエストを行うクライアント・アプリケーションの作成を簡素化します。

  • SOAPリクエストの作成および基礎となる転送プロトコルを使用したリクエスト送信の詳細をカプセル化します。

  • プラガブルな転送をサポートし、クライアントは転送を簡単に変更できます(HTTPおよびHTTPSによる転送が可能ですが、このリリースでサポートされるのはHTTP 1.0のみです)。

SOAPクライアントでリクエストの送信やレスポンスの受信を行うには、次の手順を実行する必要があります。

  1. サービスの起動にすべての必要なパラメータを収集します。

  2. SOAPプロトコルに従って作成されるXMLメッセージである、SOAPサービスのリクエスト・メッセージを作成します。これは、XMLでエンコードされたすべての入力パラメータのすべての値を含みます。このプロセスをシリアライズと呼びます。

  3. SOAPサーバーがサポートする転送プロトコルを使用してリクエストをSOAPサーバーに送信します。

  4. SOAPレスポンス・メッセージを受信します。

  5. SOAP Fault要素を処理して、リクエストの成否を判断します。

  6. XMLから戻されたパラメータをネイティブなデータ型に変換します。このプロセスをデシリアライズといいます。

  7. 必要に応じて結果を使用します。

SOAPサーバーの使用

SOAPサーバーでは、SOAPサービス・リクエストの実行時に次の手順が実行されます。

  1. SOAPサーバーは、サービス・リクエストを受信します。

  2. XMLリクエストの解析後、メッセージを実行するか、拒否するかを決定します。

  3. メッセージを実行する場合、リクエストされたサービスが存在するかどうかを判断します。

  4. すべての入力パラメータをXMLからサービスが認識できるデータ型に変換します。

  5. サービスを起動します。

  6. 戻りパラメータをXMLに変換し、SOAPレスポンス・メッセージを生成します。

  7. レスポンス・メッセージをコール元に戻します。

SOAP C関数

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リファレンス』を参照してください。

SOAPの例1: XML文書の送信

次に、旅行会社に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コンテキスト、xctxXmlCreate()で作成し、このコンテキストを使用してSOAPコンテキスト、ctxXmlSoapCreateCtx()で作成します。

  • メッセージを作成するために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);
}

SOAPの例2: 明確化を求めるレスポンス

旅行会社は、旅行者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

SOAPの例3: POSTの使用

最後の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