zoukankan      html  css  js  c++  java
  • C++ XML

    写Unmanaged Code在.NET时代成为一种很悲惨的事,当你需要处理XML文件时,这种感觉会变得尤其强烈。FCL中的System.Xml多简单啊,连Steve Ballmer都知道怎么用。

    事情不会总是那么理想的,如果你要在C/C++程序里处理XML怎么办呢?

    选择一:市面上的XML lib还是有几个的,最有名的当然是libxml。我一年前用过,很不错,我还特意写了一份简明教程,后来不知搁哪儿了。

    写Unmanaged Code在.NET时代成为一种很悲惨的事,当你需要处理XML文件时,这种感觉会变得尤其强烈。FCL中的System.Xml多简单啊,连Steve Ballmer都知道怎么用。
    事情不会总是那么理想的,如果你要在C/C++程序里处理XML怎么办呢?
    选择一:市面上的XML lib还是有几个的,最有名的当然是libxml。我一年前用过,很不错,我还特意写了一份简明教程,后来不知搁哪儿了。
    选择二:MS的MSXML,我要介绍的就是这个。
    先说一下在MSDN哪里找文档吧,往下看的时候也好有个参考:在Index里打:Windows Media Services 9 Series SDK=>Programming Reference=>Programming Reference (C++)=>XML DOM Interfaces (C++)。什么?Windows Media?呵呵,不错,我觉得这个guide反而是最清楚的,你直接找MSXML,得到的结果,我觉得还没这个好。
    在C程序里调用MSXML基本就是一堆COM接口,不过在Visual Studio里操作先要做点简单的设置:
    在你的Project里Add References=>COM标签=>Microsoft XML v4.0,5.0其实也有了,但因为是和Office一起发布的,觉得有点怪,不想用,反正也未必用什么很怪异的功能,4.0可以了。
    然后在加入这两行:
    #include <msxml2.h>
    #import <msxml4.dll>
    头文件和dll库。什么?在哪里加?头文件或者c/cpp文件啊,哪里合适放哪儿。
    然后就开始编程了,先定义两个必用的变量:
    IXMLDOMDocumentPtr xmlFile = NULL;
    IXMLDOMElement* xmlRoot = NULL;
    为什么是必用的?  汗...
    第一步当然是初始化COM:
    if(FAILED(CoInitialize(NULL))) ....
    接下来初始化xmlFile对象:
    if(FAILED(xmlFile.CreateInstance("Msxml2.DOMDocument.4.0"))) ...
    然后就可以加载xml文件了:
    _variant_t varXml(L"C://test.xml"); //L for unicode
    VARIANT_BOOL varOut;
    xmlFile->load(varXml, &varOut);
    取得root element:
    xmlFile->get_documentElement(&xmlRoot))
    取得第一级element:
    IXMLDOMNodeList* xmlChildNodes = NULL;
    xmlRoot->get_childNodes(&xmlChildNodes);
    遍历所有第一级element:
    IXMLDOMNode* currentNode = NULL;
    while(!FAILED(xmlChildNodes->nextNode(¤tNode)) && currentNode != NULL)
    {
    //do something
    }
    取得当前element的名称:
    BSTR nodeName;
    currentNode->get_nodeName(&nodeName);
    取得当前element的一个attribute(假设这个attribute叫type)的值:
    IXMLDOMNamedNodeMap* attributes = NULL;
    IXMLDOMNode* attributeName = NULL;
    _bstr_t bstrAttributeName = "type";
    BSTR nameVal;
    currentNode->get_attributes(&attributes);
    attributes->getNamedItem(bstrAttributeName, &attributeName);
    attributeName->get_text(&nameVal);
    需要注意的是,你要记住释放所有的借口,IXMLDOM***->Release(),这可不是.NET,有人帮你GC,你得自己调用Release()来减reference count,it's COM, remember?
    好了,大致就这样,顺便提一下XPath:
    _bstr_t bstrXmlQuery = L"/books/book[@type=scifi and @author=fox]";
    IXMLDOMNodeList* nodes = NULL;
    if(FAILED(xmlRoot->selectNodes(bstrXmlQuery, &nodes)) || FAILED(nodes->get_length(&length)) || length == 0)
    //no match found or something went wrong
    else
    //match found
    上面是找这样的node:
    <books>
    <book type="scifi" author="fox">....
    </book>
    ....
    </books>
    具体的XPath语法就查手册吧,到处都有。
    哦,对了,忘了说:如果你全部用ATL的类的话,借口的调用会简单一点,不过很容易转换的,比如:
    IXMLDOMDocument* 对应 IXMLDOMDocumentPtr(我这里用了),其他基本也是加个Ptr,我不废话了。
    最后提供一个sample,我临时攒的。工作的时候写的程序当然不能拿来贴的,呵呵。这个sample基本就是遍历整个xml,然后报告一遍文件的结构,对每个node,如果它有一个叫id的attribute,就同时打印id的值。If you want the complete VS project, shoot me an email. But I guess no one really needs it anyway, right, : )
    #include "stdafx.h"
    #include <windows.h>
    #include <msxml2.h>
    #import <msxml4.dll>
    HANDLE logFile = NULL;
    #define INDENT 4
    #define TESTHR(hr) /
    { /
    if(FAILED(hr)) goto fail; /
    }
    void PrintChild(IXMLDOMNodeList* nodeList, int level)
    {
    if(nodeList == NULL)
    return;
    IXMLDOMNode* currentNode = NULL;
    IXMLDOMNodeList* childNodes = NULL;
    IXMLDOMNamedNodeMap* attributes = NULL;
    IXMLDOMNode* attributeID = NULL;
    while(!FAILED(nodeList->nextNode(¤tNode)) && currentNode != NULL)
    {
    BSTR nodeName;
    TESTHR(currentNode->get_nodeName(&nodeName));
    DWORD dwBytesWritten;
    for(int i=0; i<level*INDENT; i++)
    WriteFile(logFile, L" ", (DWORD)(sizeof(WCHAR)), &dwBytesWritten, NULL);
    //WCHAR msg[MAX_SIZE];
    //wsprintf(msg, L"%s ", nodeName);
    WriteFile(logFile, nodeName, (DWORD)(wcslen(nodeName)*sizeof(WCHAR)), &dwBytesWritten, NULL);
    TESTHR(currentNode->get_attributes(&attributes));
    if(attributes!=NULL)
    {
    _bstr_t bstrAttributeName = "id";
    BSTR idVal;
    TESTHR(attributes->getNamedItem(bstrAttributeName, &attributeID));
    if(attributeID != NULL)
    {
    TESTHR(attributeID->get_text(&idVal));
    WriteFile(logFile, L" ", (DWORD)(sizeof(WCHAR)), &dwBytesWritten, NULL);
    WriteFile(logFile, idVal, (DWORD)(wcslen(idVal)*sizeof(WCHAR)), &dwBytesWritten, NULL);
    WriteFile(logFile, L"/r/n", (DWORD)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);
    attributeID->Release(); attributeID = NULL;
    }
    else
    {
    WriteFile(logFile, L"/r/n", (DWORD)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);
    }
    attributes->Release(); attributes = NULL;
    }
    else
    {
    WriteFile(logFile, L"/r/n", (DWORD)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);
    }
    TESTHR(currentNode->get_childNodes(&childNodes));
    PrintChild(childNodes, level+1);
    currentNode=NULL;
    }
    fail:
    if(childNodes!=NULL)
    childNodes->Release();
    if(attributeID!=NULL)
    attributeID->Release();
    if(attributes!=NULL)
    attributes->Release();
    if(currentNode != NULL)
    currentNode->Release();
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    IXMLDOMDocumentPtr xmlFile = NULL;
    IXMLDOMElement* xmlRoot = NULL;
    _variant_t varXml(L"C://demo1.xml");
    logFile = CreateFile(L"log.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(logFile == INVALID_HANDLE_VALUE)
    goto fail;
    TESTHR(CoInitialize(NULL));
    TESTHR(xmlFile.CreateInstance("Msxml2.DOMDocument.4.0"));
    VARIANT_BOOL varOut;
    TESTHR(xmlFile->load(varXml, &varOut));
    TESTHR(xmlFile->get_documentElement(&xmlRoot));
    BSTR rootName;
    DWORD dwBytesWritten;
    TESTHR(xmlRoot->get_nodeName(&rootName));
    WriteFile(logFile, rootName, (DWORD)(wcslen(rootName)*sizeof(WCHAR)), &dwBytesWritten, NULL);
    WriteFile(logFile, L"/r/n", (DWORD)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);
    IXMLDOMNodeList* xmlChildNodes = NULL;
    TESTHR(xmlRoot->get_childNodes(&xmlChildNodes));
    PrintChild(xmlChildNodes, 2);
    fail:
    if(logFile != INVALID_HANDLE_VALUE)
    CloseHandle(logFile);
    if(xmlChildNodes!=NULL)
    xmlChildNodes->Release();
    if(xmlRoot!=NULL)
    xmlRoot->Release();
    return 0;
    }

    二法

    C++操作XML编程实例

    C 2008-06-19 21:43:07 阅读31 评论0   字号: 订阅

    #include <iostream>

    #import <msxml.dll> //引入类型库

    using namespace std;

     

    int Exit();

    void LoadFromString();

    void CreateXML();

    //XML文本模板

    _bstr_t XMLTemple="<China><Beijing>-11</Beijing><Shanghai Weather=/"Cloudy/">9</Shanghai></China>";

     

    int main()

    {

    cout << " XML编程--示范程序 " << endl;

    CoInitialize(NULL); //初始化COM 环境

    cout << "------生成新的XML文本 ------" << endl;

    CreateXML();

    cout << "------读取已有XML文本 ------" << endl;

    LoadFromString();

    return Exit();

    }

     

    void CreateXML()

    {

    MSXML::IXMLDOMDocumentPtr pDoc;

    HRESULT hr =pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));

    if(!SUCCEEDED(hr))

    {

    cout << "无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!" << endl;

    Exit();

    }

    MSXML::IXMLDOMElementPtr pDocElement=pDoc->createElement("China");

    pDoc->appendChild(pDocElement);

    cout << "生成树根:/n" << pDoc->xml << endl;

    MSXML::IXMLDOMElementPtr pNewChildElement;

    pNewChildElement=pDoc->createElement("Beijing");

    pNewChildElement->Puttext("-11");

    pDocElement->appendChild(pNewChildElement);

    cout << "添加节点:/n" << pDoc->xml << endl;

    pNewChildElement=pDoc->createElement("Shanghai");

    pNewChildElement->Puttext("9");

    pNewChildElement->setAttribute("Weather",_variant_t("Cloudy"));

    pDocElement->appendChild(pNewChildElement);

    cout << "再添加节点:/n" << pDoc->xml << endl;

    pDocElement->removeChild (pNewChildElement);

    cout << "把刚加入的节点删除:/n" << pDoc->xml << endl;

    }

     

    void LoadFromString()

    {

    MSXML::IXMLDOMDocumentPtr pDoc;

    HRESULT hr =pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));

    if(!SUCCEEDED(hr))

    {

    cout << "无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!" << endl;

    Exit();

    }

    pDoc->loadXML(XMLTemple);

    cout << "读取结果:/n" << pDoc->xml << endl;

    MSXML::IXMLDOMElementPtr pDocElement=pDoc->GetdocumentElement();

    MSXML::IXMLDOMElementPtr pElement=pDocElement->selectSingleNode("Shanghai");

    pDocElement->removeChild(pElement);

    cout << "定位删除Shanghai节点:/n" << pDoc->xml << endl;

    cout << "保存结果 Save .....(模拟而已)" << endl;

    cout << "/n 好了,就这么简单" << endl;

    }

     

    int Exit()

    {

    getchar();

    return 1;

    }


     

     

    三法

     

     

    C++标准库中没有操作XML的方法,用C++操作XML文件必须熟悉一种函数库,选用LIBXML2

    Libxml2是一个C语言的XML程序库,可以简单方便的提供对XML文档的各种操作,并且支持XPATH查询,以及部分的支持XSLT转换等功能。

    Libxml2的下载地址是http://xmlsoft.org/

    windows版本的的下载地址是http://www.zlatkovic.com/libxml.en.html

    libxml2库依赖iconv和zlib库,所以需要下载三个

    成功版本libxml2-2.6.30.win32.zip、zlib-1.2.3.win32.zip和iconv-1.9.2.win32.zip。

    解压,在系统变量path中加上 iconv-1.9.2.win32/bin;zlib-1.2.3.win32/bin;libxml2-2.6.30.win32/bin这三个地址。或者把其中的三个dll到拷贝到system32目录中

    编译链接基于libxml2的程序,在VC环境中设置lib和include路径,并在link设置中添加libxml2.lib和iconv.lib.

    vc:项目->属性->c/c++->常规->附加包含目录,将三个文件夹的include下的.h头文件包含进工程

    项目->属性->链接器->常规->附加库目录,将三个文件夹的bin下的.lib库文件包含进工程

    注意,这只是将目录包含进工程,需要使用时需在代码中写

    #include <libxml/parser.h>(eg)

    #pragma   comment(lib,"libxml2.lib")(eg)

    实验代码如下

    /********************************************************************

        created:   2007/11/09

        created:   9:11:2007   15:34

        filename: CreateXmlFile.cpp

        author:       Wang xuebin

        depend:       libxml2.lib

        build:     nmake TARGET_NAME=CreateXmlFile

        purpose:   创建一个xml文件

    *********************************************************************/

    #pragma   comment(lib,"libxml2.lib")
    #pragma   comment(lib,"iconv.lib")

    #include <stdio.h>

    #include <libxml/parser.h>

    #include <libxml/tree.h>

    #include <iostream>
    using namespace std;

    int main()

    {

        //定义文档和节点指针

        xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0");

        xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST"root");

        //设置根节点

        xmlDocSetRootElement(doc,root_node);

        //在根节点中直接创建节点

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode1", BAD_CAST "newNode1 content");

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode2", BAD_CAST "newNode2 content");

        xmlNewTextChild(root_node, NULL, BAD_CAST "newNode3", BAD_CAST "newNode3 content");

        //创建一个节点,设置其内容和属性,然后加入根结点

        xmlNodePtr node = xmlNewNode(NULL,BAD_CAST"node2");

        xmlNodePtr content = xmlNewText(BAD_CAST"NODE CONTENT");

        xmlAddChild(root_node,node);

        xmlAddChild(node,content);

        xmlNewProp(node,BAD_CAST"attribute",BAD_CAST "yes");

        //创建一个儿子和孙子节点

        node = xmlNewNode(NULL, BAD_CAST "son");

        xmlAddChild(root_node,node);

        xmlNodePtr grandson = xmlNewNode(NULL, BAD_CAST "grandson");

        xmlAddChild(node,grandson);

        xmlAddChild(grandson, xmlNewText(BAD_CAST "This is a grandson node"));

        //存储xml文档

        int nRel = xmlSaveFile("CreatedXml.xml",doc);

        if (nRel != -1)

        {

           cout<<"一个xml文档被创建,写入"<<nRel<<"个字节"<<endl;

        }

        //释放文档内节点动态申请的内存

        xmlFreeDoc(doc);

        return 1;

    }

    创建一个xml文档其流程如下:

    l         用xmlNewDoc函数创建一个文档指针doc;

    l         用xmlNewNode函数创建一个节点指针root_node;

    l         用xmlDocSetRootElement将root_node设置为doc的根结点;

    l         给root_node添加一系列的子节点,并设置子节点的内容和属性;

    l         用xmlSaveFile将xml文档存入文件;

    l         用xmlFreeDoc函数关闭文档指针,并清除本文档中所有节点动态申请的内存。

    注意,有多种方式可以添加子节点:第一是用xmlNewTextChild直接添加一个文本子节点;第二是先创建新节点,然后用xmlAddChild将新节点加入上层节点。

    产生如下文件

    <?xml version="1.0" ?>
    - -<root>
    <       <newNode1>newNode1 content</newNode1>
    <       <newNode2>newNode2 content</newNode2>
    <        <newNode3>newNode3 content</newNode3>
    <        <node2 attribute="yes">NODE CONTENT</node2>
    -        -<son>
    <               <grandson>This is a grandson node</grandson>
           </son>
    </root>

    法四

    ——需要的包
       #include <XMLDoc.hpp>
    ——相关说明
       _di_IXMLDocument  为模板类
       typedef System::DelphiInterface< IXMLDocument >  _di_IXMLDocument;

       _di_IXMLNode
       typedef System::DelphiInterface< IXMLNode >  _di_IXMLNode;

       _di_IXMLNodeList 同

    ——类方法 
    //设置参数
    void TXXX::setOptions(String name,String value){

      //创建文档对象
      _di_IXMLDocument XMLDoc = LoadXMLDocument(L"文件路径");

       XMLDoc->Active=true;

       //文档根节点
       _di_IXMLNode root = XMLDoc->DocumentElement;

       //想要查找节点
       _di_IXMLNode tempNode;
     
       //调用搜索方法
       searchXml(name,root,tempNode);
      
       // 处理
       if(tempNode!=NULL)
          tempNode->SetText(value);
          XMLDoc->SaveToFile(L"文件路径");
    }
    //递归搜索参数节点树
    void TXXX::searchXml(String name,_di_IXMLNode &Parent_Node,_di_IXMLNode& tempNode){

      _di_IXMLNode Child_Node;  //子结点
      //子节点列表
      _di_IXMLNodeList list = Parent_Node->ChildNodes;
      for(int i=0;i<list->Count;i++)
      {
         Child_Node = list->Get(i);
         //递归结束条件
         if(Child_Node->GetNodeName()==name)
         {
            tempNode = Child_Node;
            break;
         }
         else
         {
            //递归函数
            searchXml(name,Child_Node,tempNode);
         }
      }
    }
     


    法五

    写本文的目的是为了方便大家了解C++ MSXML操作方法。

    当然,C++中对MSXML的调用有多种,本文采用的方法是完全参照MSXML SDK提供的文档进行操作。

    如果有什么错误,欢迎指正。

    代码框架是基于vs2008 MFC 对话框程序(UNICODE)。对话框程序需要读者自己创建。

    view plaincopy to clipboardprint?
    #include <msxml6.h>  
    #include <comutil.h>  
    #pragma comment(lib, "comsuppwd.lib")  
    void CXmlSampleDlg::OnBnClickedButton1()//按钮事件  
    {  
        CoInitialize(NULL);  
        CComPtr<IXMLDOMDocument> spXmldoc;  
        HRESULT hr = spXmldoc.CoCreateInstance(L"MSXML2.DOMDocument.6.0");  
     
        if(SUCCEEDED(hr))  
        {  
            VARIANT_BOOL isSuccessFul;  
            CComVariant varXmlFile(L"a.xml");  
     
            spXmldoc->put_async(VARIANT_FALSE);  
            HRESULT hr= spXmldoc->load(varXmlFile, &isSuccessFul);  
     
            if(isSuccessFul==VARIANT_TRUE)  
            {  
                CComBSTR bstrXml;  
                CComPtr<IXMLDOMElement> spRoot=NULL;  
                CComPtr<IXMLDOMElement> spTheBook=NULL;  
                CComPtr<IXMLDOMElement> spTheElem=NULL;  
                CComPtr<IXMLDOMNode> spNewNode=NULL;  
     
                hr = spXmldoc->get_documentElement(&spRoot);  
                spRoot->get_xml(&bstrXml);  
                AfxMessageBox(L"1, 原始的XML");  
                AfxMessageBox(bstrXml);  
     
     
                spXmldoc->createElement(L"book", &spTheBook);  
                spXmldoc->createElement(L"name", &spTheElem);  
                spXmldoc->put_text(L"新书");  
                spTheBook->appendChild(spTheElem, &spNewNode);  
                spTheElem.Release();  
                spNewNode.Release();  
     
                spXmldoc->createElement(L"price", &spTheElem);  
                spTheElem->put_text(L"20");  
                spTheBook->appendChild(spTheElem, &spNewNode);  
                spTheElem.Release();  
                spNewNode.Release();  
     
                spXmldoc->createElement(L"memo", &spTheElem);  
                spTheElem->put_text(L"新书的更好看。");  
                spTheBook->appendChild(spTheElem, &spNewNode);  
                spNewNode.Release();  
                spTheElem.Release();  
     
                spRoot->appendChild(spTheBook, &spNewNode);  
                spNewNode.Release();  
                spTheBook.Release();  
     
                spRoot->get_xml(&bstrXml);  
                AfxMessageBox(L"2, 新建一本书完成");  
                AfxMessageBox(bstrXml);  
                ////---  新建一本书完成 ----  
     
     
                ////---  下面对《哈里波特》做一些修改。 ----  
                ////---  查询找《哈里波特》----  
                CComPtr<IXMLDOMNode> spTheNode=NULL;  
                spRoot->selectSingleNode(L"/books/book[name='哈里波特']", &spTheNode);  
                hr=spTheNode.QueryInterface(&spTheBook);  
                spTheNode.Release();  
     
                spTheBook->get_xml(&bstrXml);  
                AfxMessageBox(L"3,《哈里波特》的XML");  
                AfxMessageBox(bstrXml);  
     
                ////---  此时修改这本书的价格 -----  
                CComPtr<IXMLDOMNodeList> spNodeList=NULL;  
                CComPtr<IXMLDOMNode> spListItem=NULL;  
                spTheBook->get_childNodes(&spNodeList);  
                spNodeList->get_item(1, &spListItem);  
                spNodeList.Release();  
                spListItem->put_text(L"15");  
     
                ////---  另外还想加一个属性id,值为B01 ----  
                CComVariant varId(L"B01");  
                spTheBook->setAttribute(L"id", varId);  
                varId.Clear();  
     
                spTheBook->get_xml(&bstrXml);  
                spTheBook.Release();  
                AfxMessageBox(L"4, 对《哈里波特》修改完成。");  
                AfxMessageBox(bstrXml);  
                ////---  对《哈里波特》修改完成。 ----  
     
     
                ////---  要用id属性删除《三国演义》这本书  ----  
                spRoot->selectSingleNode(L"/books/book[@id='B02']", &spTheNode);  
                hr=spTheNode.QueryInterface(&spTheBook);  
                spTheNode.Release();  
     
                spTheBook->get_xml(&bstrXml);  
                AfxMessageBox(L"5, 《三国演义》的XML");  
                AfxMessageBox(bstrXml);  
     
                CComPtr<IXMLDOMNode> spParentNode=NULL;  
                spTheBook->get_parentNode(&spParentNode);  
                spParentNode->removeChild(spTheBook, &spTheNode);  
                spTheNode.Release();  
                spParentNode.Release();  
                spTheBook.Release();  
     
                spRoot->get_xml(&bstrXml);  
                AfxMessageBox(L"6, 删除《三国演义》后的XML");  
                AfxMessageBox(bstrXml);  
     
     
                ////---  再将所有价格低于10的书删除  ----  
                spRoot->selectNodes(L"/books/book[price<10]", &spNodeList);  
                CComQIPtr<IXMLDOMSelection> spSomeBooks=spNodeList;  
                spNodeList.Release();  
     
                spSomeBooks->removeAll();  
                spSomeBooks.Release();  
     
                spXmldoc->get_xml(&bstrXml);  
                AfxMessageBox(L"7, 已经删除价格低于10的书");  
                AfxMessageBox(bstrXml);  
     
                spRoot.Release();  
                bstrXml.Empty();  
     
                //spXmldoc->save(varXmlFile); //保存xml。  
            }  
            varXmlFile.ClearToZero();  
        }  
     
        spXmldoc.Release();  
     
        CoUninitialize();  

    #include <msxml6.h>
    #include <comutil.h>
    #pragma comment(lib, "comsuppwd.lib")
    void CXmlSampleDlg::OnBnClickedButton1()//按钮事件
    {
     CoInitialize(NULL);
     CComPtr<IXMLDOMDocument> spXmldoc;
     HRESULT hr = spXmldoc.CoCreateInstance(L"MSXML2.DOMDocument.6.0");

     if(SUCCEEDED(hr))
     {
      VARIANT_BOOL isSuccessFul;
      CComVariant varXmlFile(L"a.xml");

      spXmldoc->put_async(VARIANT_FALSE);
      HRESULT hr= spXmldoc->load(varXmlFile, &isSuccessFul);

      if(isSuccessFul==VARIANT_TRUE)
      {
       CComBSTR bstrXml;
       CComPtr<IXMLDOMElement> spRoot=NULL;
       CComPtr<IXMLDOMElement> spTheBook=NULL;
       CComPtr<IXMLDOMElement> spTheElem=NULL;
       CComPtr<IXMLDOMNode> spNewNode=NULL;

       hr = spXmldoc->get_documentElement(&spRoot);
       spRoot->get_xml(&bstrXml);
       AfxMessageBox(L"1, 原始的XML");
       AfxMessageBox(bstrXml);


       spXmldoc->createElement(L"book", &spTheBook);
       spXmldoc->createElement(L"name", &spTheElem);
       spXmldoc->put_text(L"新书");
       spTheBook->appendChild(spTheElem, &spNewNode);
       spTheElem.Release();
       spNewNode.Release();

       spXmldoc->createElement(L"price", &spTheElem);
       spTheElem->put_text(L"20");
       spTheBook->appendChild(spTheElem, &spNewNode);
       spTheElem.Release();
       spNewNode.Release();

       spXmldoc->createElement(L"memo", &spTheElem);
       spTheElem->put_text(L"新书的更好看。");
       spTheBook->appendChild(spTheElem, &spNewNode);
       spNewNode.Release();
       spTheElem.Release();

       spRoot->appendChild(spTheBook, &spNewNode);
       spNewNode.Release();
       spTheBook.Release();

       spRoot->get_xml(&bstrXml);
       AfxMessageBox(L"2, 新建一本书完成");
       AfxMessageBox(bstrXml);
       ////---  新建一本书完成 ----


       ////---  下面对《哈里波特》做一些修改。 ----
       ////---  查询找《哈里波特》----
       CComPtr<IXMLDOMNode> spTheNode=NULL;
       spRoot->selectSingleNode(L"/books/book[name='哈里波特']", &spTheNode);
       hr=spTheNode.QueryInterface(&spTheBook);
       spTheNode.Release();

       spTheBook->get_xml(&bstrXml);
       AfxMessageBox(L"3,《哈里波特》的XML");
       AfxMessageBox(bstrXml);

       ////---  此时修改这本书的价格 -----
       CComPtr<IXMLDOMNodeList> spNodeList=NULL;
       CComPtr<IXMLDOMNode> spListItem=NULL;
       spTheBook->get_childNodes(&spNodeList);
       spNodeList->get_item(1, &spListItem);
       spNodeList.Release();
       spListItem->put_text(L"15");

       ////---  另外还想加一个属性id,值为B01 ----
       CComVariant varId(L"B01");
       spTheBook->setAttribute(L"id", varId);
       varId.Clear();

       spTheBook->get_xml(&bstrXml);
       spTheBook.Release();
       AfxMessageBox(L"4, 对《哈里波特》修改完成。");
       AfxMessageBox(bstrXml);
       ////---  对《哈里波特》修改完成。 ----


       ////---  要用id属性删除《三国演义》这本书  ----
       spRoot->selectSingleNode(L"/books/book[@id='B02']", &spTheNode);
       hr=spTheNode.QueryInterface(&spTheBook);
       spTheNode.Release();

       spTheBook->get_xml(&bstrXml);
       AfxMessageBox(L"5, 《三国演义》的XML");
       AfxMessageBox(bstrXml);

       CComPtr<IXMLDOMNode> spParentNode=NULL;
       spTheBook->get_parentNode(&spParentNode);
       spParentNode->removeChild(spTheBook, &spTheNode);
       spTheNode.Release();
       spParentNode.Release();
       spTheBook.Release();

       spRoot->get_xml(&bstrXml);
       AfxMessageBox(L"6, 删除《三国演义》后的XML");
       AfxMessageBox(bstrXml);


       ////---  再将所有价格低于10的书删除  ----
       spRoot->selectNodes(L"/books/book[price<10]", &spNodeList);
       CComQIPtr<IXMLDOMSelection> spSomeBooks=spNodeList;
       spNodeList.Release();

       spSomeBooks->removeAll();
       spSomeBooks.Release();

       spXmldoc->get_xml(&bstrXml);
       AfxMessageBox(L"7, 已经删除价格低于10的书");
       AfxMessageBox(bstrXml);

       spRoot.Release();
       bstrXml.Empty();

       //spXmldoc->save(varXmlFile); //保存xml。
      }
      varXmlFile.ClearToZero();
     }

     spXmldoc.Release();

     CoUninitialize();
    }

    a.xml

    view plaincopy to clipboardprint?
    <?xml version="1.0" encoding="UTF-8"?> 
    <books> 
     <book> 
      <name>哈里波特</name> 
      <price>10</price> 
      <memo>这是一本很好看的书。</memo> 
     </book> 
     <book id="B02"> 
      <name>三国演义</name> 
      <price>10</price> 
      <memo>四大名著之一。</memo> 
     </book> 
     <book id="B03"> 
      <name>水浒</name> 
      <price>6</price> 
      <memo>四大名著之一。</memo> 
     </book> 
     <book id="B04"> 
      <name>红楼</name> 
      <price>5</price> 
      <memo>四大名著之一。</memo> 
     </book> 
    </books>  
    <?xml version="1.0" encoding="UTF-8"?>
    <books>
     <book>
      <name>哈里波特</name>
      <price>10</price>
      <memo>这是一本很好看的书。</memo>
     </book>
     <book id="B02">
      <name>三国演义</name>
      <price>10</price>
      <memo>四大名著之一。</memo>
     </book>
     <book id="B03">
      <name>水浒</name>
      <price>6</price>
      <memo>四大名著之一。</memo>
     </book>
     <book id="B04">
      <name>红楼</name>
      <price>5</price>
      <memo>四大名著之一。</memo>
     </book>
    </books> 
     


    法六

    在 Kenn Scribner 近期有关 XML 和 MSXML DOM 分析器的文章中,仅介绍了该分析器的部分功能。这些文章将 XML 作为一种进行了说明,但是并没有介绍 XML 分析器本身。现在,Kenn 将回过头来介绍 MSXML 分析器,并讲解处理 XML 文档和节点所需的基本知识:搜索特定的节点、插入节点和检索节点值。

    MSXML 分析器基于 XML 文档对象模型,对于查看表 1 中所示的各种文档对象来说,它非常重要。这些对象直接出自 XML 规范本身。MSXML 还可以进一步将 XML DOM 对象合并到 COM 中。因此,弄清楚哪个 XML DOM 对象对应于哪个 MSXML COM 接口非常容易。例如,IXMLDOMNode 代表称为 Node 的 DOM 对象。

    表 1. XML DOM 对象及其用途DOM 对象用途

    DOMImplementation

    一个查询对象,用于确定 DOM 支持的级别

    DocumentFragment

    表示树的一部分。

    任一种情况下,搜索的结果都是一个 MSXML 节点对象 IXMLDOMNode。文档中必须存在该节点,否则搜索将失败。我的应用程序使用该节点作为一个全新 XML 节点的父级,该新节点是由 XML 文档对象创建的:

    CComPtrIXMLDOMNode spXMLChildNode;

    hr = spXMLDOM-createNode,

    CComBSTR,

    NULL,

    &spXMLChildNode);

    if)

    throw Unable to create xmlchildnode XML node;

    if

    throw Unable to create xmlchildnode XML node;

    如果分析器可以创建该节点,下一步就是将它放到 XML 树中。IXMLDOMNode::appendChild 正是完成这一任务的方法:

    CComPtrIXMLDOMNode spInsertedNode;

    hr = spXMLNode-appendChild;

    if)

    throw Unable to move xmlchildnode XML node;

    if

    throw Unable to move xmlchildnode XML node;

    如果父节点的确将新创建的节点插入为其子级,将返回另一个 IXMLDOMNode 实例,该实例表示新的子节点。实际上,该新子节点和传递给 appendChild 的节点是同一个 XML 节点。由于在存在问题时附加的子节点的指针将为 Null,因此,检查该指针很有用。

    到目前为止,我找到了一个特定的节点,并为它创建了一个新的子节点,下面,让我们看看如何处理属性。假定您要将该属性添加到新的子节点:

    xml=fun

    这并不难,但是您必须从 IXMLDOMNode 切换到 IXMLDOMElement,以便该子节点的元素特征。在实践中,这意味着您必须查询 IXMLDOMNode 接口的相关 IXMLDOMElement 接口,查明后,再调用 IXMLDOMElement::setAttribute:

    CComQIPtrIXMLDOMElement spXMLChildElement;

    spXMLChildElement = spInsertedNode;

    if

    throw Unable to query for xmlchildnode XML _

    element interface;

    hr = spXMLChildElement-setAttribute,

    CComVariant);

    if)

    throw Unable to insert new attribute;

    此时,已经修改了 XML 树,并创建了所需的树。应用程序可以在这个时候将文档保存到磁盘,或者执行其他任务。现在,让我们来搜索另一个节点并显示该节点所包含的值(文本)。您已经了解了如何搜索节点,因此,我们将直接讲解提取。

    提取节点的关键在于使用 IXMLDOMNode::get_nodeTypedValue。可以使用 Microsoft 类型架构来标识节点所包含的,因此可以方便地存储浮点值、整数、字符串或该架构所支持的任何类型。可以使用 dt:type 属性来指定类型,如下所示:

    model dt:type=stringSL-2/model

    year dt:type=int1992/year

    如果特定的节点具有指定的类型,就可以使用 get_nodeTypedValue 以该格式提取。如果未指定类型,将假定为文本,分析器将返回具有 BSTR 的 VARIANT。在本例中,这没有任何问题,因为我们要搜索的节点是一个实际上包含一个字符串的文本节点。在需要时,始终可以使用 atoi 等方法将字符串转换为其他形式。本例中,我们只是提取该字符串并显示它:

    CComVariant varValue;

    hr = spXMLNode-get_nodeTypedValue;

    if)

    throw Unable to retrieve xmltext text;

    if

    else

    如果能够检索与节点关联的值,并且该值为 BSTR(预期的类型),我们将在屏幕上显示该文本。如果不能,将显示一条错误消息,不过,根据情况而定,可以方便地采取其他操作。

    最后一项与 XML 有关的操作是将已更新的 XML 树保存到磁盘,这一任务是使用 IXMLDOMDocument::save 完成的:

    hr = spXMLDOM-save);

    if)

    throw Unable to save updated XML document;

    完成保存后,向屏幕写一条简短说明,并退出。

    这个示例应用程序无论如何都算不上漂亮。您可以让自己的应用程序执行很多其他功能,但我希望您通过这个简短的示例了解到了如何从 C++ 程序使用 MSXML 分析器。该分析器本身是一个复杂的软件,无论怎样强调使用 MSDN Library 作为参考,都不能算是过份。该分析器公开了许多接口,这些接口通常会公开许多方法。即便如此,我在自己的项目中仍频繁地使用该分析器,在亲自编写了一些代码并进行试验后,我发现这个软件制作很精良 并且便于使用。我希望您也同样会发现该分析器和一般意义上的 XML 具有广泛的用途。

  • 相关阅读:
    我与ARM的那些事儿1初识ARM
    WP的万能小应用时钟表
    单片机的模拟智能灌溉系统
    android的计算器
    C语言经典面试题目(转的,不过写的的确好!)
    数据库sqlite3在linux中的使用
    认识域模型
    认识JMS
    认识JDOM
    认识RMI
  • 原文地址:https://www.cnblogs.com/zhiweiyouzhishenghuo/p/5005502.html
Copyright © 2011-2022 走看看