史上最も信頼性が高く、MSXMLベースのXML解析ガイド-C++


史上最も信頼性が高く、MSXMLベースのXML解析ガイド-C++
最近はC++関連のプロジェクトをしていて、COMとMSXMLを併用してXMLファイルの情報を解析する問題に遭遇していますが、このような問題はMFC開発でもよく使われています.ネットで丸ごと検索してみると、確かに利用可能なcodeを見つけるのは難しいので、やっと自分で効率的で簡単な方法を研究して、この機会にまとめて、みんなに共有します.
付VS Projectミラー:SimpleParser 4 MSXML-cpp:C++言語で書かれたMSXMLの簡単な使用例、COMとMFC開発でよく使われています.https://github.com/yanglr/Sim...「Raw」をクリックするとソースが表示されます.forkまたはstarを歓迎します.
まずMSXML技術の基本的な特徴を簡単に列挙する.
COMの技術に基づいて、Windowsオペレーティングシステムに付属するXMLを処理する.
MSXML
DOM本体実装を提供し、XPathとXSLTをサポートします.
SAX 2ベースのイベントを含むアナライザ.
プロセス設計
まず、大まかな流れを簡単に紹介します.
  • 初期化COM
  • IDOMDocumentオブジェクトxmlDocを作成し、xmlDoc->load()またはloadXML()メソッドを使用してXMLソース
  • を読み込む
  • selectNodes()またはselectSingleNode()関数を呼び出し、指定したノードオブジェクトを選択します.
  • ノードオブジェクトの内容は、IXMLDOMNodeオブジェクトの属性および方法によって読み取られる.
  • ノードオブジェクトの内容は、IXMLDOMNodeオブジェクトの属性およびメソッドによって設定される.
  • xmlDoc->save()を呼び出してXMLファイルを保存します.
  • COM
  • を閉じる
    解決すべき問題:
  • xml情報のいくつかの読み取り形式(xmlファイルまたはwchar)
  • ノードをどのように選択し、andノード属性を取得するにはどのような方法がありますか?
  • IXMLDOMNodeとIXMLDOMElementインタフェースの関連と違いは何ですか?
  • ノードが配列であれば、どのように操作しますか?
  • プロパティにプロパティを挿入する方法
  • 文字列の変換
  • xml情報にはどのような読み取り形式がありますか(xmlファイルまたはwchar)
  • xmlファイル
  • ファイルからxmlコンテンツをインポートしurlまたはfilePathを使用
    VARIANT_BOOL bSuccess = false;
    HRESULT hr = iXMLDoc->load(CComVariant(L"./test.xml"), &bSuccess); //    L    

    変数方式で人filePathを渡す場合は、c_を使用する必要があります.str()関数を変換します.コードは次のとおりです.
    VARIANT_BOOL bSuccess = false;
    filePath = "./test.xml";
    HRESULT hr = iXMLDoc->load(CComVariant(filePath.c_str()), &bSuccess);
  • 文字列形式で読み込まれたxmlフルコード
  • まずBSTR定数を定義します
    const wchar_t *src = L""
    L"\r
    " L"\r
    " L" Hey\r
    " L" \r
    " L" \r
    " L" \r
    " L" \r
    " L"
    \r
    " L"
    \r
    ";

    次に、BSTRからxmlコンテンツをインポートします.
    VARIANT_BOOL bSuccess = false;
    iXMLDoc->loadXML(CComBSTR(src), &bSuccess);

    注意:BSTR文字列はCOMコンポーネントオブジェクトモデルの文字列形式で、文字列の長さを表す4バイトの整数で始まり、UTF-16符号化wchar_に続くt文字列(0終了フラグを含む).BSTRタイプの変数は、文字列の最初の文字を指すポインタです.
    どのようにノードを選択して、andノードの属性を取るにはどのような方法がありますか?
  • 検索ノード名
  • CComBSTR sstrRoot(L"root"); // sstrRoot("root");
    CComPtr rootNode;
    HRESULT hr = iXMLDoc->selectSingleNode(sstrRoot, &rootNode);
    CComPtr textNode;
    hr = rootNode->selectSingleNode(CComBSTR(L"text"), &textNode); //      "text"  

    IXMLDOMNodeとIXMLDOMElementインタフェースの関連性と違い
    IXMLDOMElementインタフェースはIXMLDOMNodeインタフェースに継承されますが、IXMLDOMNodeインタフェースから継承する方法に加えて、IXMLDOMElementインタフェースは次の方法にも露出します.
    方法
    説明
    get_tagName
    要素名(tag間のテキスト)を取得します.
    getAttribute
    指定した名前の属性の値を取得します.
    getAttributeNode
    指定した名前の属性を取得するノード
    getElementsByTagName
    指定した名前に一致するすべてのサブ要素のリストを取得します.
    removeAttribute
    指定した名前の属性の移動または置換
    removeAttributeNode
    この要素から指定した属性を除去
    setAttribute
    指定した名前の属性に値を設定
    setAttributeNode
    指定した属性ノードをこの要素に追加または置換します.
    ノードが配列の場合、どのように操作しますか?
    get_を先に使用childNodes関数はサブノードのリストを取得し、get_を使用して巡回します.itemは各項目を順次取り出して処理する.
        CComPtr pRootElement;
        CComPtr pNodeList;
        pRootElement->get_childNodes(&pNodeList); // Child node list
        long nLen;
        pNodeList->get_length(&nLen);    // Child node list
        for (long index = 0; i != nLen; ++index) // Traverse
        {
            CComPtr pCurNode;
            hr = pNodeList->get_item(index, &pCurNode);
            do();  //             
        }

    属性の挿入方法
    Element->setAttribute()を使用すると、次のようになります.
    CComPtr imageElement;
    xmlDocData->createElement(CComBSTR(L"Image"), &imageElement); //     "Image"
    imageElement->setAttribute(CComBSTR(L"Type"), CComVariant(CComBSTR(imageType.c_str())));  //     "Type"

    文字列の変換と出力
  • はprintf関数+"%ls"またはwprintf関数+"%s"を直接使用してBSTRクラス文字列
  • を印刷する.
        CComBSTR ssName;
        printf("Node name:%ls
    ", ssName); // %ls BSTR SysFreeString(ssName); //

    または
        CComBSTR ssName;
        wprintf(L"Node name:%s
    ", ssName); // L SysFreeString(ssName);
  • CComBSTRクラス文字列の内容をwstringにコピーし、wcout出力
       CComBSTR ssName;
       wstring bstrText(ssName);
       wcout << bstrText << endl;
  • を使用する.
  • CComBSTRクラス文字列をLPCTSTRタイプに強く変換した後、wcout出力
  • を使用する.
    CStringWクラスの文字列では、これは比較的簡単な方法です.
       CComBSTR ssName;
       CString cstring(ssName);
       wcout << (LPCTSTR)cstring << endl;
  • CComBSTRクラス文字列の内容をCW 2 Aクラス文字列(マルチバイト文字列)にコピーし、wcout出力
  • を使用する.
    CComBSTR ssName;
    CW2A printstr(ssName);
    cout << printstr << endl;

    プライマリコード
    #include    //    MSXML   
    #include 
    #include "atlstr.h"  //   CString, CStringW CW2A
    #include   //   wcout  
    #include     //    c_str()  , wcout
    #include "comutil.h" //   _bstr_t
    using namespace std;
    
    const wchar_t *src = L""
    L"\r
    " L"\r
    " L" Hey\r
    " L" \r
    " L" \r
    " L" \r
    " L" \r
    " L"
    \r
    " L"
    \r
    "; int main() { CoInitialize(NULL); // Initialize COM CComPtr iXMLDoc; // Or use CComPtr, CComPtr try { HRESULT hr = iXMLDoc.CoCreateInstance(__uuidof(DOMDocument)); // iXMLDoc.CoCreateInstance(__uuidof(DOMDocument60)); // Load the file. VARIANT_BOOL bSuccess = false; // Load it from a url/filename... hr = iXMLDoc->load(CComVariant(L"./test.xml"), &bSuccess); // filePath = "./test.xml"; // hr = iXMLDoc->load(CComVariant(filePath.c_str()), &bSuccess); // or from a BSTR... // iXMLDoc->loadXML(CComBSTR(src), &bSuccess); // Get a smart pointer (sp) to the root CComPtr pRootElement; hr = iXMLDoc->get_documentElement(&pRootElement); // Root elements // Get Attribute value of the note "root" CComBSTR ssDesc("desc"); CComVariant deVal(VT_EMPTY); hr = pRootElement->getAttribute(ssDesc, &deVal); CComBSTR sstrRoot(L"root"); // sstrRoot("root"); CComPtr rootNode; hr = iXMLDoc->selectSingleNode(sstrRoot, &rootNode); // Search "root" CComBSTR rootText; hr = rootNode->get_text(&rootText); if (SUCCEEDED(hr)) { wstring bstrText(rootText); wcout << "Text of root: " << bstrText << endl; } CComPtr descAttribute; hr = rootNode->selectSingleNode(CComBSTR("@desc"), &descAttribute); // Atrribute @, @ CComBSTR descVal; hr = descAttribute->get_text(&descVal); if (SUCCEEDED(hr)) { wstring bstrText(descVal); wcout << "Desc Attribute: " << bstrText << endl; } if (!FAILED(hr)) { wstring strVal; if (deVal.vt == VT_BSTR) strVal = deVal.bstrVal; wcout << "desc: " << strVal << endl; } CComPtr pNodeList; pRootElement->get_childNodes(&pNodeList); // Child node list long nLen; pNodeList->get_length(&nLen); // Child node list for (long i = 0; i != nLen; ++i) // Traverse { CComPtr pNode; hr = pNodeList->get_item(i, &pNode); CComBSTR ssName; CComVariant val(VT_EMPTY); hr = pNode->get_nodeName(&ssName); if (SUCCEEDED(hr)) { wstring bstrText(ssName); wcout << "Name of node " << (i + 1) << ": " << bstrText << endl; CString cstring(ssName); // To display a CStringW correctly, use wcout and cast cstring to (LPCTSTR), an easier way to display wide character strings. wcout << (LPCTSTR)cstring << endl; // CW2A converts the string in ccombstr to a multi-byte string in printstr, used for display output. CW2A printstr(ssName); cout << printstr << endl; } } /// Add(Append) node CComPtr& xmlDocData(iXMLDoc); CComPtr imageElement; CComPtr newImageNode; string imageType = "jpeg"; char buffer[MAX_PATH]; GetCurrentDirectory(MAX_PATH, buffer); // Get Current Directory string path(buffer); // Copy content of char*, generate a string string imagePath = path + "\\com.jpg"; xmlDocData->createElement(CComBSTR(L"Image"), &imageElement); imageElement->setAttribute(CComBSTR(L"Type"), CComVariant(CComBSTR(imageType.c_str()))); // imageElement->setAttribute(CComBSTR(L"FileName"), CComVariant(CComBSTR(imagePath.c_str()))); rootNode->appendChild(imageElement, &newImageNode); /// Remove "text" node under "root" node CComPtr xmlOldNode; CComPtr textNode; hr = rootNode->selectSingleNode(CComBSTR(L"text"), &textNode); // Search "text" node hr = rootNode->removeChild(textNode, &xmlOldNode); /// Update XML hr = iXMLDoc->save(CComVariant("updated.xml")); } catch (char* pStrErr) { // Some error... std::cout << pStrErr << std::endl << std::endl; } // catch catch (...) { // Unknown error... std::cout << "Unknown error..." << std::endl << std::endl; } // Release() - that gets done automatically, also can manually do for each opened node or elements. // iXMLDoc.Release(); // Stop COM CoUninitialize(); system("pause"); return 0; }

    実行結果:
    実行が完了し、取得したupdate.xmlの内容は次のとおりです.https://raw.githubusercontent...参考資料:
  • IXMLDOMElementインタフェース
  • Using the MSXML Parser
  • MFC C++ XML Parse - Using MSXML
  • は、さまざまな文字列タイプ間の変換|Microsoft Docs
  • 本文は本人csdnブログに掲載されています→https://blog.csdn.net/lzuacm/...