前のページ次のページ上に戻るホーム BREW C++ ライブラリ & GUI フレームワーク & XML ミドルウェア : SophiaFramework UNIVERSE 5.0

18.7. サンプルコード

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

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

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

例 18.3. 要素の取得

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

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

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

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

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

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

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

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

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

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

    // ノードの名前を取得する ( resultString は "apple" になる )
    resultString = textNode->GetNodeValue();

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

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

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

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

例 18.4. 複数ノードの取得

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

// file.xml に保存した XML 文書を解析する
if ((error = parser.Parse("/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 関数を使います。

例 18.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>

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

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

// file.xml に保存した XML 文書を解析する
if ((error = parser.Parse("/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 関数を使って順次取得します。

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

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

例 18.8. 属性の取得

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

// file.xml に保存した XML 文書を解析する
if ((error = parser.Parse("/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 ノードの値(属性値)を取得する
        resultString = attr->GetNodeValue();
        
        // すべての Attribute ノード を取得する
        SFXXMLNode::DOMNamedNodeMapPtr nodeMap = element->GetAttributes();

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

        // Attribute ノードの値(属性値)を取得する
        resultString = attr->GetNodeValue();
    }
}
[Note] 注意
Attribute ノードの値(属性値)を取得するには SFXXMLElement::GetAttribute 関数を使います。

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 文書のファイルとして保存します。

例 18.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;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

例 18.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" は生成されません。

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

SAX パーサー (SFXXMLSAXParser) はイベント駆動型の XML パーサーです。SAX パーサーは XML 文書を先頭から解析していき、タグや属性が現れるたびにイベントを発生させます。ユーザーはイベント発生時に実行させたい関数 (ハンドラ) をあらかじめ SAX パーサーに登録しておきます。

SFXXMLDefaultHandler クラスを継承するハンドラ クラスを定義して、SAX パーサーに登録します。

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

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

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

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

    // 各ハンドラの宣言

    // データの内容を取得するハンドラ
    virtual Void Characters(SFXAnsiStringConstRef string, BoolConst cdataSection = true);
    virtual Void EndDocument(Void);
    virtual Void EndElement(SFXAnsiStringConstRef uri = SFXAnsiString::EmptyInstance(), SFXAnsiStringConstRef localname =  SFXAnsiString::EmptyInstance(), SFXAnsiStringConstRef qname = SFXAnsiString::EmptyInstance());
    virtual Void StartDocument(Void);
    virtual Void StartElement(SFXAnsiStringConstRef uri,SFXAnsiStringConstRef localname, SFXAnsiStringConstRef qname, SFXXMLGrammar::XMLAttrListConstRef attrList);
    virtual Void IgnorableWhitespace(SFXAnsiStringConstRef string);
    virtual Void ProcessingInstruction(SFXAnsiStringConstRef target, SFXAnsiStringConstRef data);
    virtual Void EndPrefixMapping(SFXAnsiStringConstRef  prefix);
    virtual Void StartPrefixMapping(SFXAnsiStringConstRef prefix, SFXAnsiStringConstRef uri);

    // 解析用のハンドラ
    virtual Void Comment(SFXAnsiStringConstRef string);
    virtual Void EndCDATA(Void);
    virtual Void EndDTD(Void);
    virtual Void EndEntity(SFXAnsiStringConstRef name);
    virtual Void StartCDATA(Void);
    virtual Void StartDTD(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId);
    virtual Void StartEntity(SFXAnsiStringConstRef name);

    // DTD 宣言に関するハンドラ
    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);

    // エラーの通知を取得するハンドラ
    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::ProcessingInstruction(SFXAnsiStringConstRef target, SFXAnsiStringConstRef data)
{
    return;
}
// 接頭辞と URI 名前空間マッピングのスコープの終了通知を受け取るハンドラ
Void MyXMLHandler::EndPrefixMapping(SFXAnsiStringConstRef  prefix)
{
    return;
}
// 接頭辞と URI 名前空間マッピングのスコープの開始通知を受け取るハンドラ
Void MyXMLHandler::StartPrefixMapping(SFXAnsiStringConstRef  prefix, SFXAnsiStringConstRef uri)
{
    return;
}
// コメントの通知を受け取るハンドラ
Void MyXMLHandler::Comment(SFXAnsiStringConstRef string)
{
    return;
}
// CDATA セクションの終了通知を受け取るハンドラ
Void MyXMLHandler::EndCDATA(Void)
{
    return;
}
// DTD 宣言の終了通知を受け取るハンドラ
Void MyXMLHandler::EndDTD(Void)
{
    return;
}
// エンティティの終了通知を受け取るハンドラ
Void MyXMLHandler::EndEntity(SFXAnsiStringConstRef name)
{
    return;
}
// CDATA セクションの開始通知を受け取るハンドラ
Void MyXMLHandler::StartCDATA(Void)
{
    return;
}
// DTD 宣言の開始通知を受け取るハンドラ
Void MyXMLHandler::StartDTD(SFXAnsiStringConstRef name, SFXAnsiStringConstRef publicId, SFXAnsiStringConstRef systemId)
{
    return;
}
// エンティティの開始通知を受け取るハンドラ
Void MyXMLHandler::StartEntity(SFXAnsiStringConstRef name)
{
    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::ElementDecl(SFXAnsiStringConstRef name, SFXAnsiStringConstRef model)
{
    return;
}
// ATTLIST 宣言の通知を受け取るハンドラ
Void MyXMLHandler::AttributeDecl(SFXAnsiStringConstRef ename, SFXAnsiStringConstRef aname, SFXAnsiStringConstRef type, SFXAnsiStringConstRef mode, SFXAnsiStringConstRef value) 
{
    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;
}

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

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

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

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

例 18.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 クラスのインスタンスに格納します。

例 18.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>

例 18.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 クラスのインスタンスに格納します。

18.7.3. DTD 付き XML 文書の解析

例 18.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>

例 18.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.">

例 18.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();
}

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

例 18.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"));

18.7.5. SOAP

例 18.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);
    }

}

例 18.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>

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

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

関連情報 : SFCErrorEnum

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

#define AMAZON_ID " // Amazon の ID を設定する

SFMTYPEDEFCLASS(SOAPTest)
class SOAPTest : public SFCApplication {
    SFMSEALCOPY(SOAPTest)
private:
    SFXSOAPRPC _rpc;    // SOAP-RPC プロトコルを扱う変数

    Void OnSOAP(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 SOAPTest::OnSOAP()
{
    // メソッド名を設定する
    _rpc.SetMethodName("ItemSearch");
    
    // SOAP エンコーディングを設定する
    _rpc.SetEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
    // 下記のように記述してもよい
	// _rpc.SetEncodingStyle("STANDARD");

    // ターゲットとなる URI を設定する
    _rpc.SetTargetObjectURI("https://webservices.amazon.com/");

    // Web サービスのパラメータを設定する
    _rpc.AddParameter("AWSAccessKeyId", 
                      SFXBuffer(SFXAnsiString(AMAZON_ID)));
    _rpc.AddParameter("Keywords", 
                      SFXBuffer(SFXAnsiString("caviar")));
    _rpc.AddParameter("MerchantId", 
                      SFXBuffer(SFXAnsiString("Amazon")));
    _rpc.AddParameter("SearchIndex", 
                      SFXBuffer(SFXAnsiString("GourmetFood")));

    // Web サービスを呼び出す
    _rpc.Invoke("http://soap.amazon.co.jp/onca/soap?Service=AWSECommerceService",
                "http://soap.amazon.com",
                OnResultSHP_SOAP,
                this);
}

// Web サービスの結果の通知を受け取るコールバック関数
// error: エラー値, result: Web サービスの戻り値, fault: SOAP Fault 要素, soap : SOAP メッセージ, reference: コールバック関数に渡されるデータ
Void SOAPTest::OnResultSHP_SOAP(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap, VoidPtr reference)
{
    static_cast<SOAPTestPtr>(reference)->OnResult_SOAP(error, result, fault, soap);
}

// Web サーバーから受信した SOAP メッセージを処理する関数
Void SOAPTest::OnResult_SOAP(SFCError error, const SFXSOAPRPC::Params& result, const SFXSOAPRPC::FAULT& fault, SFXSOAPParserConstRef soap)
{
    if (error == SFERR_NO_ERROR) {

        // SOAP メッセージの結果(result: SFXSOAPRPC::Params 配列)をパラメータに分けて取得する

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

        while (paramEtor.HasNext()) {

            // 各パラメータを取得する
            SFXSOAPRPC::LPPARAMETER temp = paramEtor.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()));
            }
        }
   }
   // エラーメッセージ( SOAP Fault )を表示する
   else if (error == SFERR_SOAP_FAULT_MESSAGE) {

        if(!fault._faultactor.IsEmpty())
            // faultactor 要素が空でないとき、その内容を表示する
            TRACE("faultactor: %s", fault._faultactor.GetCString());    

        if(!fault._faultcode.IsEmpty())
            // faultcode 要素が空でないとき、その内容を表示する
            TRACE("faultcode: %s", fault._faultcode.GetCString());     

        if(!fault._faultstring.IsEmpty())
            // faultstring 要素が空でないとき、その内容を表示する
            TRACE("faultstring: %s", fault._faultstring.GetCString());  

        if (fault._faultdetail) 
             // detail 要素が空でないとき、その内容を表示する
            TRACE("faultstring: %s", fault._faultdetail->GetText().GetCString());
    }
    return;
}

18.7.6. WSDL

例 18.24. SFXSOAPServiceProxy クラス ( WSDL ) を使った Web サービス

// WSDL 文書を利用してプロキシを作成し、ダイナミックバイディングを行う変数
SFXSOAPServiceProxy _wsdl;

// サーバーからの返答を受け取るためのコールバック関数を設定する
_wsdl.SetNotifyHandler(OnResultSHP, this);

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

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

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

    // Web サービスのメソッド名を設定する
    _wsdl.SetMethodName("GetWeatherByCity");

    // パラメータの値を設定する
    // Web サービスのユーザープロパティを設定する
    _wsdl.SetParameterValue("UserID", 
                            SFXBuffer(SFXAnsiString("sophia@s-cradle.com")));
    _wsdl.SetParameterValue("Password", 
                            SFXBuffer(SFXAnsiString("*******")));

    // Web サービスのパラメータを設定する
    _wsdl.SetParameterValue("CityName", 
                            SFXBuffer(SFXAnsiString("Washington")));
    _wsdl.SetParameterValue("StateAbbreviationORCountryName", 
                            SFXBuffer(SFXAnsiString("PA")));

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

例 18.25. Web サービス (HTTPS)

// WSDL を利用してプロキシを作成し、ダイナミックバイディングを行う変数
SFXSOAPServiceProxy _wsdl;

// サーバーからの返答を受け取るためのコールバック関数を設定する
_wsdl.SetNotifyHandler(OnResultSHP, this);

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

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

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

    // Web サービスのメソッド名を設定する
    _wsdl.SetMethodName("getRate");

    // Web サービスのパラメータを設定する
    _wsdl.SetParameterValue("CurrencyCode", SFXBuffer(SFXAnsiString("JPY")));

    // SSL の検証モードを設定する
    _wsdl.SetTrustMode(SSL_TRUST_MODE_CHECK);

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

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

解説
0x69A6 WSDL 文書で指定した Web サービスがありません。
0x69A7 WSDL 文書で指定した Web サービスのポートがありません。
0x69A8 WSDL 文書で指定した Web サービスのポートにバインドできません。
0x69A9 WSDL 文書で指定したWeb サービスのメソッドがありません。
0x69AA 該当するポートタイプがありません。
0x69AB WSDL該当するメッセージがありません。
0x0106 ファイルシステムに空き要領がありません。
[Note] XML エラーメッセージ

関連情報 : SFCErrorEnum