Result GetFirstElementByTagName(MSXML::IXMLDOMElementPtr& parent, const string& tagName, MSXML::IXMLDOMElementPtr& pEl) { Result r; try { pEl = 0; MSXML::IXMLDOMNodeListPtr pList = parent->getElementsByTagName(tagName.c_str()); if(pList == NULL) { r.Fail(Format("No '%' nodes found (pList = 0)").s(tagName).Str()); } else { if(!pList->length) { r.Fail(Format("No '%' nodes found (length = 0)").s(tagName).Str()); } else { pEl = pList->nextNode(); r.Succeed(); } } } catch(_com_error& e) { r.Fail(Format("Com error: % %").s(e.ErrorMessage()).s(e.Description()).Str()); } return r; }
/* * ----- main ----- */ int main(int argc, char* argv[]) { if ( argc != 2 ) { cerr << "fsm <URL for FSM>" << endl; return 1; } if ( FAILED(CoInitialize(0)) ) { cerr << "Can't initialize COM" << endl; return 1; } try { /* * XML Parser の生成と初期化 */ MSXML::IXMLDOMDocumentPtr document("MSXML.DOMDocument"); document->validateOnParse = VARIANT_TRUE; // 検証を行う document->async = VARIANT_FALSE; // Parse完了までloadメソッドをブロック /* * 引数に与えられたURLで示されたXMLをロードする */ document->load(argv[1]); /* * Parseエラーがあれば出力 */ MSXML::IXMLDOMParseErrorPtr error = document->parseError; if ( error->errorCode != 0 ) { if ( error->line ) { cerr << "line : " << error->line << endl; cerr << "position : " << error->linepos << endl; cerr << "source : " << (const char*)error->srcText << endl; } cerr << "URL : " << (const char*)error->url << endl; cerr << "code : " << error->errorCode << endl; cerr << "reason : " << (const char*)error->reason << endl; return 1; } /* * ルートエレメントを取得する */ MSXML::IXMLDOMElementPtr root = document->documentElement; /* * 全イベントを取り出す */ set<string> event_set; MSXML::IXMLDOMNodeListPtr events = root->getElementsByTagName("Event"); for ( int i = 0; i < events->length; ++i ) { MSXML::IXMLDOMElementPtr node = events->item[i]; event_set.insert(get_attribute(node,"name")); } /* * 初期状態 / 終了状態 を取得する */ string state_name = get_attribute(root,"initial"); string terminal_name = get_attribute(root,"terminal"); string fsm_name = get_attribute(root,"name"); cout << "FSM : " << fsm_name << endl; /* * 状態遷移表を駆動する */ while ( state_name != terminal_name ) { /* * state_name で示される State を見つける */ MSXML::IXMLDOMElementPtr state = find_element(root,"name",state_name); if ( state == 0 ) { cerr << "can't find state : " << state_name << endl; break; } /* * 現在の状態とイベント一覧を出力する */ cout << "state : " << state_name << endl; cout << "enter an event ("; copy(event_set.begin(), event_set.end(), ostream_iterator<string>(cout,",")); cout << "exit) ? " << flush; /* * ユーザからのイベント入力 */ string event_name; cin >> event_name; if ( event_name == "exit" ) break; if ( event_set.find(event_name) == event_set.end() ) { cerr << event_name << " is not valid." << endl; continue; } /* * event_name で示される Event を見つける */ MSXML::IXMLDOMElementPtr event = find_element(state,"name",event_name); if ( event == 0 ) { cerr << "can't find event : " << event_name << endl; break; } /* * アクションを実行する */ string action_name = get_attribute(event,"action"); if ( action_name != "none" ) cout << "action : " << action_name << endl; /* * 次の状態へ遷移する */ string transition_name = get_attribute(event,"transition"); if ( transition_name != "none" ) state_name = transition_name; } } catch ( _com_error& ex ) { cerr << "COM error occurred : " << ex.ErrorMessage() << endl; } CoUninitialize(); return 0; }