前のページ次のページ上に戻るホーム SophiaFramework UNIVERSE 5.3

19.7. サンプルコード

19.7.1. DOM パーサーによる XML 文書の解析

例 19.2. 解析対象の XML 文書 ( file.xml )

<fruit>
  <name>apple</name>
  <size>XS</size>
  <color>red</color>
</fruit>

例 19.3. 要素の取得

SFCError error;             // エラー値
SFXXMLDOMParser parser;     // DOM パーサー
SFXAnsiString resultString; // ノードの名前を格納する変数

// file.xml に保存した XML 文書を解析する
if ((error = parser.Parse(SFXPath("/file.xml"))) == SFERR_NO_ERROR) {

    // DOM ツリーのルートノードを取得する
    SFXXMLDocumentPtr root = parser.GetDocument(); 

    // ルートノードの最初の子ノードを取得する:  "fruit" ノード
    SFXXMLNodePtr child = root->GetFirstChild();   

    // "fruit" ノードの名前を取得する: "fruit" 
    resultString = child->GetNodeName();

    // "fruit" ノードのノードタイプを取得する: ELEMENT_NODE
    SFXXMLNode::NodeType type = child->GetNodeType();

    // "fruit" ノードの最初の子ノードを取得する: "name" ノード
    SFXXMLNodePtr node = child->GetFirstChild();   

    // ノードの名前を取得する: "name"
    resultString = node->GetNodeName();

    // ノードタイプを取得する: ELEMENT_NODE
    type = node->GetNodeType();

    // "name" ノードの最初の子ノードを取得する: "apple" ノード
    SFXXMLNodePtr textNode = node->GetFirstChild(); 

    // ノードの値を取得する: "apple"
    resultString = textNode->GetNodeValue();

    // ノードタイプを取得する: TEXT_NODE
    type = textNode->GetNodeType();

    // "name" ノードの、次の兄弟ノードを取得する: "size" ノード
    node = node->GetNextSibling();  

    // ノードの名前を取得する: "size"
    resultString = node->GetNodeName();

    // ノードタイプを取得する: ELEMENT_NODE
    type = node->GetNodeType();
}
[Note] 注意
ルートノードは、SFXXMLDOMParser::GetDocument 関数、 子ノードは SFXXMLNode::GetFirstChild 関数を使用して取得します。

例 19.4. 複数ノードの取得

SFCError error;             // エラー値
SFXXMLDOMParser parser;     // DOM パーサー
SFXAnsiString resultString; // ノードの名前を格納する変数

// file.xml に保存した XML 文書を解析する
if ((error = parser.Parse(SFXPath("/file.xml"))) == SFERR_NO_ERROR) {

    // DOM ツリーのルートノードを取得する
    SFXXMLDocumentPtr root = parser.GetDocument(); 

    // ルートノードの最初の子ノード ( "fruit" ノード ) を取得する
    SFXXMLNodePtr child = root->GetFirstChild(); 

    // "fruit" ノードのすべての子ノードを取得する
    // SFXXMLNode::DOMNodeListPtr は SFXList<SFXXMLNodePtr> と同じ
    SFXXMLNode::DOMNodeListPtr nodeList = child->GetChildNodes();

    // イテレータを取得する
    SFXXMLNode::DOMNodeList::Iterator itor = nodeList->GetFirstIterator();

    while (itor.HasNext()) { // 次のノードがあるかぎり繰り返す

        // "name" ノード、"size" ノード、"color" ノードの順に取得できる

        SFXXMLNodePtr node = itor.GetNext();

        // ノードの名前を取得する
        resultString = node->GetNodeName();

        // ノードのテキストを取得する ( "name" ノードの場合は "apple"、"size" ノードの場合は "XS" )
        resultString = node->GetText();
    }

    // "color" というタグ名を持つすべての Element ノードを取得する
    nodeList = static_cast<SFXXMLElementPtr>(child)->GetElementsByTagName("color"); 

    // イテレータを取得する
    itor = nodeList->GetFirstIterator(); 

    // 各 Element ノードに対する処理
    while (itor.HasNext()) { 

        // 次の Element ノードを取得する
        SFXXMLNodePtr node = itor.GetNext(); 

        // ...

    }
}
[Note] 注意

すべての子ノードを取得するには、 SFXXMLNode::GetChildNodes 関数を呼び出します。

例 19.5. 解析対象の XML 文書 ( file.xml )

<fruits>
    <fruit>
        <name>apple</name>
        <size>XS</size>
        <color>red</color>
    </fruit>
    <fruit>
        <name>banana</name>
        <size>S</size>
        <color>yellow</color>
    </fruit>
    <fruit>
        <name>melon</name>
        <size>XS</size>
        <color>green</color>
    </fruit>
</fruits>

例 19.6. 各ノードに対する処理

SFCError error;         // エラー値
SFXXMLDOMParser parser; // DOM パーサー

// file.xml に保存した XML 文書を解析する
if ((error = parser.Parse(SFXPath("/file.xml"))) == SFERR_NO_ERROR) {

    // DOM ツリーのルートノードを取得する
    SFXXMLDocumentPtr root = parser.GetDocument(); 

    // ルートノードの最初の子ノード ( "fruits" ノード ) を取得する
    SFXXMLNodePtr child = root->GetFirstChild();   

    // "fruits" ノードの最初の子ノード( "fruit" ノード)を取得する
    SFXXMLNodePtr node = child->GetFirstChild();   

    // "fruit" ノードの各子ノードに対する処理
    while (node != null) {

        // 最初の子ノード( "name" ノード)を取得する
        SFXXMLNodePtr nameNode = node->GetFirstChild();   

        // ノードのテキストを取得する
        SFXAnsiString resultString = nameNode->GetText(); 

        // 次の兄弟ノードを取得する
        node = node->GetNextSibling(); 

    }
}
[Note] 注意

兄弟ノードは while ループ内で SFXXMLNode::GetNextSibling 関数を呼び出して順次取得します。

例 19.7. 解析対象の XML 文書 ( file.xml )

<fruit>
    <name language="english" code="ascii">apple</name>
    <size>XS</size>
    <color>red</color>
</fruit>

例 19.8. 属性の取得

SFCError error;             // エラー値
SFXXMLDOMParser parser;     // DOM パーサー
SFXAnsiString resultString; // 属性の値を格納する変数

// file.xml に保存した XML 文書を解析する
if ((error = parser.Parse(SFXPath("/file.xml"))) == SFERR_NO_ERROR) {

    // DOM ツリーのルートノードを取得する
    SFXXMLDocumentPtr root = parser.GetDocument(); 

    // ルートノードの最初の子ノード ( "fruit" ノード ) を取得する
    SFXXMLNodePtr child = root->GetFirstChild(); 
    
    // "fruit" ノードの最初の子ノード ( "name" ノード ) を取得する
    child = child->GetFirstChild();   

    // child ノードの名前が "name" のとき
    if (SFXAnsiString("name").Equals(child->GetNodeName())) {

        // Attribute ノードは Element ノードから取得するので、キャストの必要がある
        SFXXMLElementPtr element = static_cast<SFXXMLElementPtr>(child);

        // "language" という名前の Attribute ノードの値を取得する
        // resultString は "english" になる
        resultString = element->GetAttribute("language");

        // "language" という名前の Attribute ノード を取得する
        SFXXMLAttributePtr attr = element->GetAttributeNode("language");
        
        // Attribute ノードの値(属性値)を取得する: "english"
        resultString = attr->GetNodeValue();
        
        // すべての Attribute ノード を取得する
        SFXXMLNode::DOMNamedNodeMapPtr nodeMap = element->GetAttributes();

        // DOMNamedNodeMap から名前を指定して Attribute ノード を取得する
        attr = static_cast<SFXXMLAttributePtr>(nodeMap->GetNamedItem("code"));

        // Attribute ノードの値(属性値)を取得する: "ascii"
        resultString = attr->GetNodeValue();
    }
}
[Note] 注意

Element ノードの属性値を取得するには、 属性名を指定して SFXXMLElement::GetAttribute 関数を呼び出します。

Element ノードの Attribute ノードを取得するには、 属性名を指定して SFXXMLElement::GetAttributeNode 関数を呼び出します。

Element ノードに含まれるすべての Attribute ノードを取得するには、 SFXXMLElement::GetAttributes 関数を呼び出します。

XML 文書の作成

XML 文書は SFXXMLDocument クラスや SFXXMLElement クラスを使用して以下の手順で作成します。

  1. DOM ツリーのルートノード(SFXXMLDocument クラスのインスタンス)を作成します。
  2. XML 文書のルート要素となる Element ノード(SFXXMLElement クラスのインスタンス)を作成します。
  3. 2. で作成した Element ノードを、1. で作成したルートノードの最初の子ノードとして追加します。
  4. 必要に応じて DOM ノード(SFXXMLNode クラスを継承する SFXXMLDocument 以外のクラスのインスタンス)を作成します。
  5. ノードによっては、名前、値、属性などの情報を設定することも可能です。
  6. ルートノード、XML 文書のルート要素となる Element ノード、および 「4. と 5.で作成した DOM ノード」を使用して DOM ツリーを構築します。
  7. SFXXMLDocument::Save 関数を呼び出して、DOM ツリーを XML 文書のファイルとして保存します。

例 19.9. XML 文書の作成

SFCError error; // エラー値

// document ノード(Document ノード: DOM ツリーのルートノード)を作成する
SFXXMLDocument document;

// document ノードに XML 文書のバージョンを設定する
document.SetVersion("1.0");

// collection ノード(タグ名が "COLLECTION" の Element ノード)を作成する
SFXXMLElementPtr collection = document.CreateElement("COLLECTION");
if (collection == null) {
    return SFERR_NO_MEMORY;
}

// document ノードに collection ノードを追加する
if ((error = document.AppendChild(SFXXMLNodePtr(collection))) != SFERR_NO_ERROR) {
    return error;
}

// collection ノードに属性を追加する
collection->SetAttribute("xmlns:dt", "urn:schemas-microsoft-com:datatypes");

// date ノード(タグ名が "DATE" の Element ノード)を作成する
SFXXMLElementPtr date = document.CreateElement("DATE");
if (date == null) {
    return SFERR_NO_MEMORY;
}

// date ノードに属性を追加する
date->SetAttribute("dt:dt", "datetime");

// date ノードにテキスト情報を追加する
if ((error = date->AppendChild(SFXXMLNodePtr(document.CreateTextNode("1998-10-13T15:56:00")))) != SFERR_NO_ERROR) {
    return error;
}

// collection ノードに date ノードを追加する
if ((error = collection->AppendChild(SFXXMLNodePtr(date))) != SFERR_NO_ERROR) {
    return error;
}

// book ノード(タグ名が "BOOK" の Element ノード)を作成する
SFXXMLElementPtr book = document.CreateElement("BOOK");
if (book == null) {
    return SFERR_NO_MEMORY;
}

// collection ノードに book ノードを追加する
if ((error = collection->AppendChild(SFXXMLNodePtr(book))) != SFERR_NO_ERROR) {
    return error;
}

// "<TITLE>Cosmos</TITLE>" を作成する
SFXXMLElementPtr title = document.CreateElement("TITLE");
if (title == null) {
    return SFERR_NO_MEMORY;
}

if ((error = title->AppendChild(SFXXMLNodePtr(document.CreateTextNode("Cosmos")))) != SFERR_NO_ERROR) {
    return error;
}

if ((error = book->AppendChild(SFXXMLNodePtr(title))) != SFERR_NO_ERROR) {
    return error;
}

// "<AUTHOR>Carl Sagan</AUTHOR>" を作成する
SFXXMLElementPtr author = document.CreateElement("AUTHOR");
if (author == null) {
    return SFERR_NO_MEMORY;
}

if ((error = author->AppendChild(SFXXMLNodePtr(document.CreateTextNode("Carl Sagan")))) != SFERR_NO_ERROR) {
    return error;
}

if ((error = book->AppendChild(SFXXMLNodePtr(author))) != SFERR_NO_ERROR) {
    return error;
}

// "<PUBLISHER>Ballantine Books</PUBLISHER>" を作成する
SFXXMLElementPtr publisher = document.CreateElement("PUBLISHER");
if (publisher == null) {
    return SFERR_NO_MEMORY;
}

if ((error = publisher->AppendChild(SFXXMLNodePtr(document.CreateTextNode("Ballantine Books")))) != SFERR_NO_ERROR) {
    return error;
}

if ((error = book->AppendChild(SFXXMLNodePtr(publisher))) != SFERR_NO_ERROR) {
    return error;
}

// XML 文書を保存する
if ((error = document.Save("book.xml")) != SFERR_NO_ERROR) {
    return error;
}

例 19.10. 実行結果

<?xml version='1.0'?>
<COLLECTION
   xmlns:dt="urn:schemas-microsoft-com:datatypes">
  <DATE dt:dt="datetime">1998-10-13T15:56:00</DATE>
  <BOOK>
    <TITLE>Cosmos</TITLE>
    <AUTHOR>Carl Sagan</AUTHOR>
    <PUBLISHER>Ballantine Books</PUBLISHER>
  </BOOK>
</COLLECTION>
[Caution] エミュレーター使用時の注意

エミュレーターのファイルシステムの容量がオーバーした場合は、"book.xml" は生成されません。

19.7.2. SAX パーサーによる XML 文書の解析

SAX パーサー(SFXXMLSAXParser)は、 イベント駆動型の XML パーサーです。

SAX パーサーによる XML 文書解析では、 XML 文書を先頭から解析していき、 タグや属性が現れるたびにイベントが発生します。

そして発生したイベントの種類に応じて、 開発者は SFXXMLDefaultHandler クラスを継承して定義したハンドラクラスのハンドラ関数が呼び出されます。

このハンドラクラスは、 XML 文書を解析する前に SFXXMLSAXParser::SetDefaultHandler 関数を使用して SAX パーサーに登録する必要があります。

例 19.11. 解析対象の XML 文書 ( file.xml )

<fruit>
    <name language="english" code="ascii">apple</name>
    <size>XS</size>
    <color>red</color>
</fruit>

例 19.12. ハンドラクラスの定義と実装

// ハンドラクラス
class MyXMLHandler : public SFXXMLDefaultHandler {
public:
    explicit MyXMLHandler(Void);
    virtual ~MyXMLHandler(Void);

    // 各ハンドラの宣言

    // XML 文書の始まりと終わりを通知を取得するハンドラ
    virtual Void StartDocument(Void);
    virtual Void EndDocument(Void);

    // DTD の通知を取得するハンドラ
    virtual Void StartDTD(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId);
    virtual Void EndDTD(Void);
    virtual Void StartEntity(SFXAnsiStringConstRef name);
    virtual Void EndEntity(SFXAnsiStringConstRef name);
    virtual Void NotationDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId);
    virtual Void UnparsedEntityDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId, SFXAnsiStringConstRef notationName);
    virtual Void ElementDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef model);
    virtual Void AttributeDecl(SFXAnsiStringConstRef ename, SFXAnsiStringConstRef aname, SFXAnsiStringConstRef type, SFXAnsiStringConstRef valuedefault, SFXAnsiStringConstRef value);
    virtual Void InternalEntityDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef value);
    virtual Void ExternalEntityDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId);

    // XML インスタンス(XML 文書のデータの内容)の通知を取得するハンドラ
    virtual Void StartElement(SFXAnsiStringConstRef uri,SFXAnsiStringConstRef localname, SFXAnsiStringConstRef qname, SFXXMLGrammar::XMLAttrListConstRef attrList);
    virtual Void EndElement(SFXAnsiStringConstRef uri = SFXAnsiString::EmptyInstance(), SFXAnsiStringConstRef localname =  SFXAnsiString::EmptyInstance(), SFXAnsiStringConstRef qname = SFXAnsiString::EmptyInstance());
    virtual Void StartPrefixMapping(SFXAnsiStringConstRef prefix, SFXAnsiStringConstRef uri);
    virtual Void EndPrefixMapping(SFXAnsiStringConstRef  prefix);
    virtual Void Characters(SFXAnsiStringConstRef string, BoolConst cdataSection = true);
    virtual Void IgnorableWhitespace(SFXAnsiStringConstRef string);
    virtual Void ProcessingInstruction(SFXAnsiStringConstRef target, SFXAnsiStringConstRef data);
    virtual Void Comment(SFXAnsiStringConstRef string);
    virtual Void StartCDATA(Void);
    virtual Void EndCDATA(Void);

    // エラーの通知を取得するハンドラ
    virtual Void ErrorReport(SFCErrorConst error, SFXAnsiStringConstRef errInfo);
};

// コンストラクタ
MyXMLHandler::MyXMLHandler(Void)
{
    return;
}

// デストラクタ
MyXMLHandler::~MyXMLHandler(Void)
{
    return;
}

// 文書の開始通知を受け取るハンドラ
Void MyXMLHandler::StartDocument(Void)
{
    TRACE("document start");
}

// 文書の終了通知を受け取るハンドラ
Void MyXMLHandler::EndDocument(Void)
{
    TRACE("document end");
}

// 要素の開始通知を受け取るハンドラ
Void MyXMLHandler::StartElement(SFXAnsiStringConstRef uri, SFXAnsiStringConstRef localname, SFXAnsiStringConstRef qname, SFXXMLGrammar::XMLAttrListConstRef attrList)
{
    // 要素名を表示する
    TRACE("element: %s start", qname.GetCString());
    
    // 要素の最初の属性対応する列挙子を取得する
    SFXXMLGrammar::XMLAttrList::Enumerator etor = attrList.GetFirstEnumerator();
    
    // すべての属性の名前と値を表示する
    while (etor.HasNext()) {
        SFXXMLGrammar::LPXMLATTR attr = etor.GetNext();     // 次の属性を取得する
        
        TRACE("attrname: %s", attr->_attName.GetCString());  // 属性の名前を表示する
        TRACE("attrvalue: %s", attr->_value.GetCString());   // 属性の値を表示する
    }
}

// 要素の終了通知を受け取るハンドラ
Void MyXMLHandler::EndElement(SFXAnsiStringConstRef uri, SFXAnsiStringConstRef localname, SFXAnsiStringConstRef qname)
{
    TRACE("element: %s end", qname.GetCString());
}

// 文字データの通知を受け取るハンドラ
Void MyXMLHandler::Characters(SFXAnsiStringConstRef string, BoolConst /*cdataSection*/)
{
    TRACE("text: %s", string.GetCString());
    return;
}

// 以下は空のハンドラ(イベントを無視する場合も定義する必要がある)

// 不要な空白文字の通知を受け取るハンドラ
Void MyXMLHandler::IgnorableWhitespace(SFXAnsiStringConstRef string)
{
    return;
}

// コメントの通知を受け取るハンドラ
Void MyXMLHandler::Comment(SFXAnsiStringConstRef string)
{
    return;
}

// CDATA セクションの開始通知を受け取るハンドラ
Void MyXMLHandler::StartCDATA(Void)
{
    return;
}

// CDATA セクションの終了通知を受け取るハンドラ
Void MyXMLHandler::EndCDATA(Void)
{
    return;
}

// 処理命令の通知を受け取るハンドラ
Void MyXMLHandler::ProcessingInstruction(SFXAnsiStringConstRef target, SFXAnsiStringConstRef data)
{
    return;
}

// 名前空間接頭辞と URI 名前空間マッピングのスコープの開始通知を受け取るハンドラ
Void MyXMLHandler::StartPrefixMapping(SFXAnsiStringConstRef  prefix, SFXAnsiStringConstRef uri)
{
    return;
}

// 名前空間接頭辞と URI 名前空間マッピングのスコープの終了通知を受け取るハンドラ
Void MyXMLHandler::EndPrefixMapping(SFXAnsiStringConstRef  prefix)
{
    return;
}

// DTD 宣言の開始通知を受け取るハンドラ
Void MyXMLHandler::StartDTD(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId)
{
    return;
}

// DTD 宣言の終了通知を受け取るハンドラ
Void MyXMLHandler::EndDTD(Void)
{
    return;
}

// エンティティの開始通知を受け取るハンドラ
Void MyXMLHandler::StartEntity(SFXAnsiStringConstRef name)
{
    return;
}

// エンティティの終了通知を受け取るハンドラ
Void MyXMLHandler::EndEntity(SFXAnsiStringConstRef name)
{
    return;
}

// 要素型宣言の通知を受け取るハンドラ
Void MyXMLHandler::ElementDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef model)
{
    return;
}

// ATTLIST 宣言の通知を受け取るハンドラ
Void MyXMLHandler::AttributeDecl(SFXAnsiStringConstRef ename, SFXAnsiStringConstRef aname, SFXAnsiStringConstRef type, SFXAnsiStringConstRef mode, SFXAnsiStringConstRef value) 
{
    return;
}

// 記法宣言の通知を受け取るハンドラ
Void MyXMLHandler::NotationDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId)
{
    return;
}

// 処理命令の通知を受け取るハンドラ
Void MyXMLHandler::UnparsedEntityDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId, SFXAnsiStringConstRef notationName)
{
    return;
}

// 内部エンティティ宣言の通知を受け取るハンドラ
Void MyXMLHandler::InternalEntityDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef value)
{
    return;
}

// 外部エンティティ宣言の通知を受け取るハンドラ
Void MyXMLHandler::ExternalEntityDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId)
{
    return;
}

// エラーの通知を受け取るハンドラ
Void MyXMLHandler::ErrorReport(SFCErrorConst error, SFXAnsiStringConstRef errInfo)
{
    return;
}

例 19.13. SAX パーサーの使い方

SFCError error;             // エラー値
SFXXMLSAXParser parser;     // SAX パーサー
MyXMLHandler handler;       // イベントハンドラ

// ハンドラを設定する
parser.SetDefaultHandler(&handler);

// XML 文書を解析する
error = parser.Parse(SFXPath("/file.xml"));

例 19.14. 実行結果

document start
element: fruit start
element: name start
attrname: language
attrvalue: english
attrname: code
attrvalue: ascii
text: apple
element: name end
element: size start
text: XS
element: size end
element: color start
text: red
element: color end
element: fruit end
document end
parse end

次に、各要素を SFXProperty クラスのインスタンスに格納します。

例 19.15. 解析対象の XML 文書 ( file.xml )

<fruits>
  <fruit>
    <name>apple</name>
    <size>XS</size>
    <color>red</color>
  </fruit>
  <fruit>
    <name>grape</name>
    <size>SS</size>
    <color>purple</color>
  </fruit>
  <fruit>
    <name>peach</name>
    <size>M</size>
    <color>pink</color>
  </fruit>
  <fruit>
    <name>pineapple</name>
    <size>LL</size>
    <color>yellow</color>
  </fruit>
</fruits>

例 19.16. ハンドラ クラスの定義と実装

// ハンドラ クラス
class MyXMLHandler : public SFXXMLDefaultHandler {
private:
    // 要素のペアを格納するクラス
    SFXProperty _property;
    // name タグの中身を一時保存する
    SFXAnsiString _name;
    // size タグの中身を一時保存する
    SFXAnsiString _size;
    // タグの種類
    enum KindOfTag {NOTHING, NAME, SIZE, COLOR};
    // 現在解析しているタグの種類
    KindOfTag _kind;
public:
    // 以後の処理は SAX パーサー ハンドラ クラスの定義と同じ

};

// コンストラクタ
MyXMLHandler::MyXMLHandler(Void)
{
    _kind = NOTHING;
    return;
}

// 要素の開始通知を受け取るハンドラ
Void MyXMLHandler::StartElement(SFXAnsiStringConstRef uri,
    SFXAnsiStringConstRef localname, SFXAnsiStringConstRef qname,
    SFXXMLGrammar::XMLAttrListConstRef attrList)
{
    if (qname.Equals("name")) { 
        // タグの名前が name のとき
        _kind = NAME; // name タグを解析中であることを表す
    }
    else if (qname.Equals("size")) {
        _kind = SIZE;
    }
    else if (qname.Equals("color")) {
        _kind = COLOR;
    }
    return;
}

// 要素の終了通知を受け取るハンドラ
Void MyXMLHandler::EndElement(SFXAnsiStringConstRef uri,
    SFXAnsiStringConstRef localname, SFXAnsiStringConstRef qname)
{
    if (qname.Equals("fruit")) { 
        // fruit タグの終わりのとき
        // _name, _size に保存しておいたテキストを格納する
        _property.Append(_name, _size);
    }
    _kind = NOTHING;
    return;
}

// 文字データの通知を受け取るハンドラ
Void MyXMLHandler::Characters(SFXAnsiStringConstRef string, BoolConst /*cdataSection*/)
{
    switch (_kind) {
        case NAME: // name を解析中のとき
            _name = string; // テキストを _name に格納する
            break;
        case SIZE:
            _size = string;
            break;
        default:
            break;
    }
    return;
}

XML 文書の各 name 要素と size 要素のテキストをペアにして SFXProperty インスタンスに格納します。

19.7.3. DTD 付き XML 文書の解析

例 19.17. 解析対象の XML 文書 ( file.xml )

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE Mail SYSTEM "personal.dtd">
<Mail>
  <From>&name;</From>
  <To>Receiver</To>
  <Cc>&Email;</Cc>
  <Date> Thu, 7 Oct 1999 11:15:16 -0600</Date>
  <Subject>XML Introduction</Subject>
  <Body>Comments:<P align = "right">Thanks for reading<br/>this article</P>
    <br/>
    <P>Hope you enjoyed this article</P>
    <P>&copyright;</P>
  </Body>
</Mail>

例 19.18. 検証用の DTD ファイル ( personal.dtd )

<?xml encoding="ISO-8859-1"?>

<!-- @version: 10.1-->

<!ELEMENT Mail (From, To, Cc?, Date?, Subject, Body)>
<!ELEMENT From (#PCDATA)>
<!ELEMENT To (#PCDATA)>
<!ELEMENT Cc (#PCDATA)>
<!ELEMENT Date (#PCDATA)>
<!ELEMENT Subject (#PCDATA)>
<!ELEMENT Body (#PCDATA | P | Br)*>
<!ELEMENT P (#PCDATA | br)*>
<!ATTLIST P align (left | right | justify) "left">
<!ELEMENT br EMPTY>
<!ENTITY  name "sophia">
<!ENTITY  Email "&name;@s-cradle.com">
<!ENTITY  copyright "Copyright (C) 2005 - 2006 Sophia Cradle Incorporated.">

例 19.19. DTD 付き XML 文書の解析

SFXXMLDOMParser parser;
SFCError error;

// DTD 付きの XML 文書を解析するため、文法タイプを設定する
parser.SetGrammar(SFXXMLGrammar::GRAMMAR_DTD);

// XML 文書を DTD で検証するように設定する
parser.SetValidationDTD(true);

// 外部 DTD を読み込むように設定する
parser.SetLoadExternalDTD(true);

// XML 文書を解析する
error = parser.Parse(SFXPath("/file.xml"));

if (error == SFERR_NO_ERROR) {
    // ルートノードを取得する
    SFXXMLDocumentPtr root = parser.GetDocument();

    // ドキュメント型を取得する
    SFXXMLDocumentTypePtr documentType = root->GetDocumentType();

    // 外部サブセット ( external DTD subset ) のシステム識別子を取得する
    // id は "personal.dtd" になる
    SFXAnsiString id = documentType->GetSystemID();

    // DTD に定義されているエンティティを DOMNamedNodeMap として取得する
    SFXXMLNode::DOMNamedNodeMapPtr entitymap = documentType->GetEntities();

    // "name" エンティティの値を取得する
    // name は "sophia" になる
    SFXAnsiString name = SFXXMLEntityPtr(entitymap->
        GetNamedItem("name"))->GetValue();
}

19.7.4. スキーマ付き XML 文書の解析

例 19.20. スキーマ付き XML 文書の解析サンプルコード

SFXXMLDOMParser parser;

// コメント 要素を作成するように設定する
parser.SetCreateCommentNodes(true);

// 名前空間を処理するように設定する
parser.SetDoNamespaces(true);

// Schema 付きの XML 文書を解析するため、文法タイプを設定する
parser.SetGrammar(SFXXMLGrammar::GRAMMAR_SCHEMA);

// スキーマを処理するように設定する
parser.SetDoSchema(true);

// スキーマ付き XML 文書の XSD ファイルを指定する
// デフォルト フォルダはアプリのホームフォルダになる
parser.SetSchemaLocation("schema.xsd");

// XML 文書をスキーマで検証するように設定する
parser.SetValidationSchema(true);

// XML Schema に "annotation" 定義した要素を無視するように設定する
parser.SetIgnoreAnnotations(false);

// XML 文書を解析する
error = parser.Parse(SFXPath("/file.xml"));

19.7.5. SOAP

例 19.21. SOAP メッセージの作成

SFXSOAPWriter soapwriter;   // SOAP メッセージの各要素を生成するオブジェクト
SFCError      error;        // エラー値を保存する変数

// Envelope 要素を作成する
// 名前空間接頭辞: デフォルトは "SOAP-ENV"
// SOAP バージョン: SFXSOAPParser::SOAP_VERSION_1_2 の場合、"http://www.w3.org/2003/05/soap-envelope"
//                  SFXSOAPParser::SOAP_VERSION_1_1 の場合、"http://schemas.xmlsoap.org/soap/envelope/" 
// SOAP エンコーディング:  "STANDARD" の場合、"http://schemas.xmlsoap.org/soap/encoding/"
//                         "NONE" の場合、SOAP エンコーディングは何も指定しない
SFXXMLElementPtr envelope = soapwriter.SetEnvelope("env", SFXSOAPParser::SOAP_VERSION_1_2, "STANDARD");


// Header 要素と Body 要素を作成する
if (envelope) {

    // xmlns:m= "http://www.example.org/timeouts" 名前空間を追加する
    error = soapwriter.AddNamespace(envelope, "m", "http://www.example.org/timeouts");
    // 名前空間が追加されているか確認する
    if(error != SFERR_NO_ERROR){
         TRACE("-----Envelope_NAMESPACE_ERROR:%d-----", error);
    }
    // faultcode、faultstring、および faultactor 要素から構成される SOAP Fault 要素を設定する(デフォルトでは Body 要素の子要素となる)
    soapwriter.SetFault("testing-fault-code","testing-fault-string","testing-fault-actor");

    // SOAP Fault 要素に detail 要素を設定する
    soapwriter.SetFaultDetail("STANDARD")->SetText("testing-fault-detail-message");

    // Header 要素を設定する
    SFXXMLElementPtr header = soapwriter.SetHeader();

    if (header) {
        // isbn:bookname="ワールドカップサッカー" 属性を追加する
        error = soapwriter.AddAttribute(header, "bookname", "http://www.example.com/ISBN", "ワールドカップサッカー", "isbn");
        // 属性が追加されているか確認する
        if(error != SFERR_NO_ERROR){
            TRACE("-----HEADER_ATTRIBUTE_ERROR:%d-----", error);
        }
           
        // xmlns:isbn="http://www.example.com/ISBN" 名前空間を追加する
        error = soapwriter.AddNamespace(header, "isbn", "http://www.example.com/ISBN");
        // 名前空間が追加されているか確認する
        if(error != SFERR_NO_ERROR){
            TRACE("-----HEADER_NAMESPACE_ERROR:%d-----", error);
        }

        // Header 要素に子要素 Upgrade を追加する
        // Upgrade 要素の名前空間は Header 要素と同じものに設定する
        SFXXMLElementPtr elem = soapwriter.SetElement(header, "Upgrade", header->GetNamespaceURI(), header->GetPrefix());

        if (elem) {
            // Upgrade 要素に子要素 SupportedEnvelope を設定する
            elem = soapwriter.SetElement(elem, "SupportedEnvelope", header->GetNamespaceURI(), header->GetPrefix());

            // SupportedEnvelope 要素の属性を追加する
            error = soapwriter.AddAttribute(elem, "qname", "http://schemas.xmlsoap.org/soap/envelope/", "ns1:Envelope");
            // 属性が追加されているか確認する
            if(error != SFERR_NO_ERROR){
                TRACE("-----UPGRADE_ATTRIBUTE_ERROR:%d-----", error);
            }
                
            // SupportedEnvelope 要素の名前空間を追加する
            error = soapwriter.AddNamespace(elem, "ns1", "http://schemas.xmlsoap.org/soap/envelope/");   
            // 名前空間が追加されているか確認する
            if(error != SFERR_NO_ERROR){
                TRACE("-----UPGRADE_NAMESPACE_ERROR:%d-----", error);
            }
        }
    }

    // 作成した SOAP メッセージを保存する
    error = soapwriter.Save("soapwriter.xml");

    // 保存されているか確認する
    if(error != SFERR_NO_ERROR){
        TRACE("-----SOAP_SAVE_ERROR:%d-----", error);
    }

}

例 19.22. 実行結果

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
              env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
              xmlns:m="http://www.example.org/timeouts">
    <env:Header isbn:bookname="ワールドカップサッカー" xmlns:isbn="http://www.example.com/ISBN">
        <env:Upgrade>
            <env:SupportedEnvelope qname="ns1:Envelope" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/"/>
        </env:Upgrade>
    </env:Header>
    <env:Body>
        <env:Fault>
            <faultcode>testing-fault-code</faultcode>
            <faultstring>testing-fault-string</faultstring>
            <faultactor>testing-fault-actor</faultactor>
            <detail env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">testing-fault-detail-message</detail>
        </env:Fault>
    </env:Body>
</env:Envelope>

表 19.21. SOAP エラーメッセージ

解説
SFERR_SOAP_EXPECT_ENVELOPE(0x699F) SOAP メッセージに Envelope 要素(SOAP Envelope)がありません。
SFERR_SOAP_EXPECT_BODY(0x69A0) SOAP メッセージに Body 要素(SOAP Body)がありません。
SFERR_SOAP_EXPECT_FAULT(0x69A1) SOAP メッセージに Fault 要素(SOAP Fault)がありません。
SFERR_SOAP_REPEATED_ENVELOPE(0x69A2) SOAP メッセージの Envelope 要素(SOAP Envelope)が重複しています。
SFERR_SOAP_REDUNDANT_ELEMENT(0x69A3) SOAP メッセージに無効な要素があります。
SFERR_SOAP_UNSUPPORT_VERSION(0x69A4) 指定された SOAP のバージョンはサポートされません。
SFERR_SOAP_FAULT_MESSAGE(0x69A5) SOAP メッセージに Fault 要素(SOAP Fault)が含まれます。
EFSFULL(0x0106) ファイルシステムに空き容量がありません。
[Note] XML エラーメッセージ

参照: SFCErrorEnum

例 19.23. SOAP-RPC による Web サービス呼び出し

SFMTYPEDEFCLASS(xmlexplainer)
class xmlexplainer : public SFCApplication {
    SFMSEALCOPY(xmlexplainer)
private:
    // SFXSOAPRPC オブジェクトはクラス変数にする
    SFXSOAPRPC _rpc;

public:
    static SFCInvokerPtr Factory(Void);
private:
    explicit xmlexplainer(Void) static_throws;
    virtual ~xmlexplainer(Void);
    virtual Bool HandleEvent(SFXEventConstRef event);
    virtual Bool HandleRender(SFXEventConstRef event);

    Void _SFXSOAPRPC(Void);

    // サーバから返答を受け取るためのコールバック関数(エントリ)
    static Void OnResultSHP_SOAP(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap, VoidPtr reference);
    // サーバから返答を受け取るためのコールバック関数(本体)
    Void OnResult_SOAP(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap);
};

Void xmlexplainer::_SFXSOAPServiceProxy(Void)
{
    // www.s-cradle.com の "Arithmetic" サービスにアクセスするコード: 
    // ※ 組み込み向けシステムの場合、メモリの制約から、WSDL ファイルのサイズは小さい方が望ましい

    // SFXSOAPServiceProxy クラスが自動生成する SOAP-RPC リクエストメッセージの内容: 2.0 と 3.0 の和を求める
    // <?xml version="1.0" encoding="UTF-8"?>
    // <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    //  <SOAP-ENV:Body>
    //   <Add xmlns="http://soapsample.s-cradle.com">
    //    <left>2.0</left>
    //    <right>3.0</right>
    //   </Add>
    //  </SOAP-ENV:Body>
    // </SOAP-ENV:Envelope>

    // 呼び出す Web サービスの機能 (メソッド) を設定する
    // ※ この場合、足し算の結果を求める
    _rpc.SetMethodName("Add");

    // 指定されたパラメータの値を設定する
    _rpc.AddParameter("left", SFXBuffer(SFXAnsiString("2.0")));
    _rpc.AddParameter("right", SFXBuffer(SFXAnsiString("3.0")));

    // Web サービスを呼び出す: 同時に、サーバから返答を受け取るためのコールバック関数(エントリ)を設定する
    // ※ コールバック関数は静的関数でなければいけないので、一旦 OnResultSHP_SOAP 静的関数を呼び出し、
    //    OnResultSHP_SOAP() 内からコールバック関数の本体である OnResult_SOAP メンバ関数を呼び出す
    _rpc.Invoke("/soapsample/Arithmetic", "urn:Add", OnResultSHP_SOAP, this);
    }
    return;
}

// サーバから返答を受け取るためのコールバック関数(エントリ)
Void xmlexplainer::OnResultSHP_SOAP(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap, VoidPtr reference)
{
    // サーバから返答を受け取るためのコールバック関数(実体)を呼び出す
    static_cast<xmlexplainerPtr>(reference)->OnResult_SOAP(error, result, fault, soap);
}

// サーバから返答を受け取るためのコールバック関数(実体)
Void xmlexplainer::OnResult_SOAP(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap)
{
    // サーバから受け取った SOAP-RPC リクエストメッセージの内容は以下の通り: 結果の 5.0 が返却される
    // <?xml version="1.0" encoding="utf-8"?>
    // <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    //  <soapenv:Body>
    //   <ns:AddResponse xmlns:ns="http://soapsample.s_cradle.com">
    //    <ns:return>5.0</ns:return>
    //   </ns:AddResponse>
    //  </soapenv:Body>
    // </soapenv:Envelope>

    // SOAP-RPC 通信が成功したか判断する
    if (error == SFERR_NO_ERROR) {

        // 方法 1: result 引数の値(SFXSOAPRPC::Params 配列)から各要素の値を取得する
        // ※ SOAP-RPC の結果は SFXSOAPRPC::Params 配列に格納されている

        // SFXSOAPRPC::Params 配列の列挙子を取得する
        SFXSOAPRPC::Params::Enumerator para = result.GetFirstEnumerator();

        while (para.HasNext()) {

            // 各要素を取得する
            SFXSOAPRPC::LPPARAMETER temp = para.GetNext();

            // パラメータの名前を取得し表示する
            TRACE("parameter-name: %s", temp->_name.GetCString());
            // パラメータのタイプを取得し表示する
            TRACE("parameter-type: %d", temp->_type);

            if (!temp->_value.IsEmpty()) {
                // パラメータの値を取得し表示する
                TRACE("parameter-value: %s", ACharConstPtr(temp->_value.GetBuffer()));
            }
        }

        // 方法 2: SFXSOAPServiceProxy::GetResultValueByName 関数で特定のパラメータを取得する

        // 指定した名前を持つメソッドレスポンス(SFXSOAPRPC::PARAMETER 構造体)を取得する
        SFXSOAPRPC::LPPARAMETER result = _wsdl.GetResultValueByName("return");

        if (result) {
            // パラメータの名前を取得し表示する パラメータの名前は "return" になる
            TRACE("result name: %s", result->_name.GetCString());

            // パラメータのタイプを取得し表示する
            TRACE("result type: %d", result->_type);

            // パラメータの値を取得し表示する (パラメータの値は 6.0 になる)
            TRACE("result value: %s", ACharConstPtr(result->_value.GetBuffer()));
        }

        // 方法 3: soap 引数の値(SFXSOAPParser 型)から SOAP-RPC の結果を取得する
        // ※ SOAP-RPC の結果 = SOAP メッセージの Body 要素(SOAP Body)の第 1 子要素の第 1 子要素
        SFXXMLElementPtr response = soap.GetRPCResult();
        // SOAP-RPC の結果を取得し表示する
        TRACE("result value: %s", response->GetText().GetCString());
    }

    // サーバ側からのエラーメッセージを取得する
    else if (error == SFERR_SOAP_FAULT_MESSAGE) {

        // faultactor 要素が空でない場合
        if (!fault._faultactor.IsEmpty())
            // faultactor 要素を表示する
            TRACE("faultactor: %s", fault._faultactor.GetCString());

        // faultcode 要素が空でない場合
        if (!fault._faultcode.IsEmpty())
            // faultcode 要素を表示する
            TRACE("faultcode: %s", fault._faultcode.GetCString());

        // faultstring 要素が空でない場合
        if (!fault._faultstring.IsEmpty())
            // faultstring 要素を表示する
            TRACE("faultstring: %s", fault._faultstring.GetCString());

        // detail 要素が null でない場合
        if (fault._faultdetail) {
            // detail 要素を表示する
            TRACE("faultstring: %s", fault._faultdetail->GetText().GetCString());
        }
    }
    return;
}

19.7.6. WSDL

以下は、加減乗除を行う Web サービスを定義する WSDL 文書(ファイル名: "Arithmetic.wsdl")です。

[Note] 注意

この Web サービスは、www.s-cradle.com でサンプルとして利用可能です。

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                  xmlns:ns1="http://org.apache.axis2/xsd" 
                  xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
                  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
                  xmlns:ns0="http://soapsample.s_cradle.com" 
                  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
                  xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
                  targetNamespace="http://soapsample.s_cradle.com">
  <wsdl:types>
    <xs:schema xmlns:ns="http://soapsample.s_cradle.com" attributeFormDefault="qualified" elementFormDefault="qualified" 
               targetNamespace="http://soapsample.s_cradle.com">
      <xs:element name="Add">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="left" nillable="true" type="xs:string"/>
            <xs:element minOccurs="0" name="right" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="AddResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="Divide">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="left" nillable="true" type="xs:string"/>
            <xs:element minOccurs="0" name="right" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="DivideResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="Multiply">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="left" nillable="true" type="xs:string"/>
            <xs:element minOccurs="0" name="right" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="MultiplyResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="Substract">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="left" nillable="true" type="xs:string"/>
            <xs:element minOccurs="0" name="right" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="SubstractResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="SubstractRequest">
    <wsdl:part name="parameters" element="ns0:Substract"/>
  </wsdl:message>
  <wsdl:message name="SubstractResponse">
    <wsdl:part name="parameters" element="ns0:SubstractResponse"/>
  </wsdl:message>
  <wsdl:message name="AddRequest">
    <wsdl:part name="parameters" element="ns0:Add"/>
  </wsdl:message>
  <wsdl:message name="AddResponse">
    <wsdl:part name="parameters" element="ns0:AddResponse"/>
  </wsdl:message>
  <wsdl:message name="DivideRequest">
    <wsdl:part name="parameters" element="ns0:Divide"/>
  </wsdl:message>
  <wsdl:message name="DivideResponse">
    <wsdl:part name="parameters" element="ns0:DivideResponse"/>
  </wsdl:message>
  <wsdl:message name="MultiplyRequest">
    <wsdl:part name="parameters" element="ns0:Multiply"/>
  </wsdl:message>
  <wsdl:message name="MultiplyResponse">
    <wsdl:part name="parameters" element="ns0:MultiplyResponse"/>
  </wsdl:message>
  <wsdl:portType name="ArithmeticPortType">
    <wsdl:operation name="Substract">
      <wsdl:input message="ns0:SubstractRequest" wsaw:Action="urn:Substract"/>
      <wsdl:output message="ns0:SubstractResponse" wsaw:Action="urn:SubstractResponse"/>
    </wsdl:operation>
    <wsdl:operation name="Add">
      <wsdl:input message="ns0:AddRequest" wsaw:Action="urn:Add"/>
      <wsdl:output message="ns0:AddResponse" wsaw:Action="urn:AddResponse"/>
    </wsdl:operation>
    <wsdl:operation name="Divide">
      <wsdl:input message="ns0:DivideRequest" wsaw:Action="urn:Divide"/>
      <wsdl:output message="ns0:DivideResponse" wsaw:Action="urn:DivideResponse"/>
    </wsdl:operation>
    <wsdl:operation name="Multiply">
      <wsdl:input message="ns0:MultiplyRequest" wsaw:Action="urn:Multiply"/>
      <wsdl:output message="ns0:MultiplyResponse" wsaw:Action="urn:MultiplyResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="ArithmeticSOAP11Binding" type="ns0:ArithmeticPortType">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <wsdl:operation name="Substract">
      <soap:operation soapAction="urn:Substract" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Add">
      <soap:operation soapAction="urn:Add" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Divide">
      <soap:operation soapAction="urn:Divide" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Multiply">
      <soap:operation soapAction="urn:Multiply" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:binding name="ArithmeticSOAP12Binding" type="ns0:ArithmeticPortType">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <wsdl:operation name="Substract">
      <soap12:operation soapAction="urn:Substract" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Add">
      <soap12:operation soapAction="urn:Add" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Divide">
      <soap12:operation soapAction="urn:Divide" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Multiply">
      <soap12:operation soapAction="urn:Multiply" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:binding name="ArithmeticHttpBinding" type="ns0:ArithmeticPortType">
    <http:binding verb="POST"/>
    <wsdl:operation name="Substract">
      <http:operation location="Arithmetic/Substract"/>
      <wsdl:input>
        <mime:content type="text/xml" part="Substract"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="Substract"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Add">
      <http:operation location="Arithmetic/Add"/>
      <wsdl:input>
        <mime:content type="text/xml" part="Add"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="Add"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Divide">
      <http:operation location="Arithmetic/Divide"/>
      <wsdl:input>
        <mime:content type="text/xml" part="Divide"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="Divide"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Multiply">
      <http:operation location="Arithmetic/Multiply"/>
      <wsdl:input>
        <mime:content type="text/xml" part="Multiply"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="Multiply"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="Arithmetic">
    <wsdl:port name="ArithmeticSOAP11port_http" binding="ns0:ArithmeticSOAP11Binding">
      <soap:address location="/soapsample/Arithmetic"/>
    </wsdl:port>
    <wsdl:port name="ArithmeticSOAP12port_http" binding="ns0:ArithmeticSOAP12Binding">
      <soap12:address location="/soapsample/Arithmetic"/>
    </wsdl:port>
    <wsdl:port name="ArithmeticHttpport" binding="ns0:ArithmeticHttpBinding">
      <http:address location="/soapsample/Arithmetic"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

以下は、 SFXSOAPServiceProxy クラスを使用して、 WSDL 文書(ファイル名: "Arithmetic.wsdl")から SOAP-RPC プロキシを生成し、 ダイナミックバイディングを行うコードです。

例 19.24. WSDL 文書から SOAP-RPC プロキシを生成し、ダイナミックバイディングを行うコード

SFMTYPEDEFCLASS(xmlexplainer)
class xmlexplainer : public SFCApplication {
    SFMSEALCOPY(xmlexplainer)
private:
    // SFXSOAPServiceProxy オブジェクトはクラス変数にする
    SFXSOAPServiceProxy _wsdl;

public:
    static SFCInvokerPtr Factory(Void);
private:
    explicit xmlexplainer(Void) static_throws;
    virtual ~xmlexplainer(Void);
    virtual Bool HandleEvent(SFXEventConstRef event);
    virtual Bool HandleRender(SFXEventConstRef event);

    Void _SFXSOAPServiceProxy(Void);

    // サーバから返答を受け取るためのコールバック関数(エントリ)
    static Void OnResultSHP_WSDL(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap, VoidPtr reference);
    // サーバから返答を受け取るためのコールバック関数(本体)
    Void OnResult_WSDL(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap);
};

Void xmlexplainer::_SFXSOAPServiceProxy(Void)
{
    // www.s-cradle.com の "Arithmetic" サービスにアクセスするコード: 
    // ※ 組み込み向けシステムの場合、メモリの制約から、WSDL ファイルのサイズは小さい方が望ましい

    // SFXSOAPServiceProxy クラスが自動生成する SOAP-RPC リクエストメッセージの内容: 2.0 と 3.0 の積を求める
    // <?xml version="1.0" encoding="UTF-8"?>
    // <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    //  <SOAP-ENV:Body>
    //   <Multiply xmlns="http://soapsample.s-cradle.com">
    //    <left>2.0</left>
    //    <right>3.0</right>
    //   </Multiply>
    //  </SOAP-ENV:Body>
    // </SOAP-ENV:Envelope>

    // サーバから返答を受け取るためのコールバック関数(エントリ)を設定する
    // ※ コールバック関数は静的関数でなければいけないので、一旦 OnResultSHP_WSDL 静的関数を呼び出し、
    //    OnResultSHP_WSDL() 内からコールバック関数の本体である OnResult_WSDL メンバ関数を呼び出す
    _wsdl.SetNotifyHandler(OnResultSHP_WSDL, this);

    // Webサービス記述言語 WSDL を設定する
    if (_wsdl.SetWSDLDocument("Arithmetic.wsdl") == SFERR_NO_ERROR) {

        // Web サービスの名前を設定する
        _wsdl.SetServiceName("Arithmetic");

        // Web サービスのポート名を設定する
        _wsdl.SetPortName("ArithmeticSOAP11port_http");

        // 呼び出す Web サービスの機能 (メソッド) を設定する
        // ※ この場合、掛け算の結果を求める
        _wsdl.SetMethodName("Multiply");

        // 指定されたパラメータの値を設定する
        _wsdl.SetParameterValue("left", SFXBuffer(SFXAnsiString("2.0")));
        _wsdl.SetParameterValue("right", SFXBuffer(SFXAnsiString("3.0")));

        // Web サービスを呼び出す
        _wsdl.Invoke();
    }
    return;
}

// サーバから返答を受け取るためのコールバック関数(エントリ)
Void xmlexplainer::OnResultSHP_WSDL(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap, VoidPtr reference)
{
    // サーバから返答を受け取るためのコールバック関数(実体)を呼び出す
    static_cast<xmlexplainerPtr>(reference)->OnResult_WSDL(error, result, fault, soap);
}

// サーバから返答を受け取るためのコールバック関数(実体)
Void xmlexplainer::OnResult_WSDL(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap)
{
    // サーバから受け取った SOAP-RPC リクエストメッセージの内容は以下の通り: 結果の 6.0 が返却される
    // <?xml version="1.0" encoding="utf-8"?>
    // <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    //  <soapenv:Body>
    //   <ns:MultiplyResponse xmlns:ns="http://soapsample.s_cradle.com">
    //    <ns:return>6.0</ns:return>
    //   </ns:MultiplyResponse>
    //  </soapenv:Body>
    // </soapenv:Envelope>

    // SOAP-RPC 通信が成功したか判断する
    if (error == SFERR_NO_ERROR) {

        // 方法 1: result 引数の値(SFXSOAPRPC::Params 配列)から各要素の値を取得する
        // ※ SOAP-RPC の結果は SFXSOAPRPC::Params 配列に格納されている

        // SFXSOAPRPC::Params 配列の列挙子を取得する
        SFXSOAPRPC::Params::Enumerator para = result.GetFirstEnumerator();

        while (para.HasNext()) {

            // 各要素を取得する
            SFXSOAPRPC::LPPARAMETER temp = para.GetNext();

            // パラメータの名前を取得し表示する
            TRACE("parameter-name: %s", temp->_name.GetCString());
            // パラメータのタイプを取得し表示する
            TRACE("parameter-type: %d", temp->_type);

            if (!temp->_value.IsEmpty()) {
                // パラメータの値を取得し表示する
                TRACE("parameter-value: %s", ACharConstPtr(temp->_value.GetBuffer()));
            }
        }

        // 方法 2: SFXSOAPServiceProxy::GetResultValueByName 関数で特定のパラメータを取得する

        // 指定した名前を持つメソッドレスポンス(SFXSOAPRPC::PARAMETER 構造体)を取得する
        SFXSOAPRPC::LPPARAMETER result = _wsdl.GetResultValueByName("return");

        if (result) {
            // パラメータの名前を取得し表示する パラメータの名前は "return" になる
            TRACE("result name: %s", result->_name.GetCString());

            // パラメータのタイプを取得し表示する
            TRACE("result type: %d", result->_type);

            // パラメータの値を取得し表示する (パラメータの値は 6.0 になる)
            TRACE("result value: %s", ACharConstPtr(result->_value.GetBuffer()));
        }

        // 方法 3: soap 引数の値(SFXSOAPParser 型)から SOAP-RPC の結果を取得する
        // ※ SOAP-RPC の結果 = SOAP メッセージの Body 要素(SOAP Body)の第 1 子要素の第 1 子要素
        SFXXMLElementPtr response = soap.GetRPCResult();
        // SOAP-RPC の結果を取得し表示する
        TRACE("result value: %s", response->GetText().GetCString());
    }

    // サーバ側からのエラーメッセージを取得する
    else if (error == SFERR_SOAP_FAULT_MESSAGE) {

        // faultactor 要素が空でない場合
        if (!fault._faultactor.IsEmpty())
            // faultactor 要素を表示する
            TRACE("faultactor: %s", fault._faultactor.GetCString());

        // faultcode 要素が空でない場合
        if (!fault._faultcode.IsEmpty())
            // faultcode 要素を表示する
            TRACE("faultcode: %s", fault._faultcode.GetCString());

        // faultstring 要素が空でない場合
        if (!fault._faultstring.IsEmpty())
            // faultstring 要素を表示する
            TRACE("faultstring: %s", fault._faultstring.GetCString());

        // detail 要素が null でない場合
        if (fault._faultdetail) {
            // detail 要素を表示する
            TRACE("faultstring: %s", fault._faultdetail->GetText().GetCString());
        }
    }
    return;
}

表 19.22. WSDL エラーメッセージ

解説
SFERR_WSDL_EXPECT_SERVICE(0x69A6) WSDL 文書に指定された service 要素がありません。
SFERR_WSDL_EXPECT_PORT(0x69A7) WSDL 文書に指定された service 要素の port 要素がありません。
SFERR_WSDL_EXPECT_BINDING(0x69A8) WSDL 文書に指定された service 要素の port 要素に binding 属性がありません。
SFERR_WSDL_EXPECT_OPERATION(0x69A9) WSDL 文書に指定された service 要素の operation 要素(メソッド)がありません。
SFERR_WSDL_EXPECT_PORTTYPE(0x69AA) WSDL 文書に指定された service 要素の port 要素の binding 属性の binding 要素の type 属性の portType 要素がありません。
SFERR_WSDL_EXPECT_MESSAGE(0x69AB) WSDL 文書に指定された service 要素の operation 要素(メソッド)に input / output 要素がありません。
EFSFULL(0x0106) ファイルシステムに空き容量がありません。
[Note] XML エラーメッセージ

参照: SFCErrorEnum