1. 介绍

    微软的msxml是基于COM接口开发的,如同vbscript和javascript一样,微软这么做是为了提供更好的扩展性。你可以在用脚本来调用msxml,也可以用C++这样编程语言一样调用(虽然这么使用是非常烦的)。

    这篇文章算是一个总结吧,我自己msxml也用的不熟,说心里话,我宁愿选择使用expat、tinyxml,而不是msxml,COM接口库很烦,为了得到一个节点的属性,你不得不首先获得一个属性集,然后再得到所要的节点,在调用get_text才能得到其值。而且特别是接口指针的释放,我做了个实验,当不释放IXMLDOMNode接口的时候,程序运行不断的泄漏内存,一会后弹出框告诉你:啥啥地址引用了非法内存...

    msxml的解析效率别指望高,如同一个软件使用stl一样。开发软件前,对xml解析库的选择应考虑在内。可以考虑:xercesc、expat、tinyxml等等。

    今天刚刚完成用C语言调用msxml来解析xml文件,趁着还没有忘记记录一下如何用非import的方式调用msxml的功能。为了方便,两个演示例子使用了C++语言,用C++主要是出于语法看起来更直接(用C需要这样:(This)->lpVtbl->Release(This))。

    好了,写着,写着,离题十万八千里了。准备好了吗?Go!

    1. msxml 设计结构
    2. msxml是基于COM的,所以就没有微软SDK API那样直接了当的函数,而是几个接口:
    1. IXMLDOMDocument2
    代表一个XML文档
    IXMLDOMNode 代表XML文档中的一个节点,可以调用IXMLDOMDocument2中的selectSingleNodes来获得一个节点。
    IXMLDOMNodeList 代表XML文档中的一个节点列表,一般在查找XML文档中一个属性值的时候,我们会首先调用IXMLDOMDocument2中的selectNodes来获得一个节点列表。
    IXMLDOMNamedNodeMap 一个节点在xml语法中代表一个用<>括起来的实体,而一般这个实体还有属性值,IXMLDOMNamedNodeMap
    就是用来表示这个的,它是一个熟悉值集合。你可以调用其getNamedItem来返回某个熟悉的值。
    IXMLDOMParseError 出错处理时用的
    IXMLHTTPRequest AJAX用的就是这个接口,一般客户端程序很少使用这个接口,这个接口实现了异步请求远程机器,然后根据结果来做相应的处理。
    IXMLDOMAttribute 属性接口,当向一个节点写入属性的时候将用到。
    IXMLDOMElement 不知道为什么造出这个接口,等我知道了在补充。在创建一个xml的时候,必须使用这个接口来创建一节点。
    IXMLDOMText <root>Hello MSXML</root>,这个接口用来控制root节点中的文本Hello MSXML的。
    IXMLDOMComment 控制xml中的注释的接口。
    1. Msdn 2005中有两个地方讲了关于msxml的编程用法:
      1. Win32 and COM Development/Graphics and Multimedia/SDK Documentation/Windows Media Services 9 Series/Programming Reference/Programming Reference (C++)/XML DOM Interfaces (C++)
      2. Win32 and COM Development/XML/MSXML/MSXML SDK/MSXML/DOM/How Do I use DOM?
    2. 对于C++程序,使用DOM有两种方式:
      1. 使用C++ 的import
    3. #import <msxml3.dll> raw_interfaces_only
      using namespace MSXML2;
    4. 2. 使用头文件msxml2.h
    5. #include <msxml2.h>
    6. 对于C程序,只能使用C++中的方式2,因为import指令是C++特有的关键字。
    7. CodeProject有一个德国人Sven Wiegand按照方式2封装的XML库 - C++ Wrapper classes for the COM interfaces of Microsoft XML parser (MSXML)。关键代码片段如下:
    1. #include "msxml2.h"
    CXMLDOMDocument2 CDOMDocumentClass::CreateXMLDOMDocument2(LPUNKNOWN pUnkOuter /*= NULL*/, DWORD dwClsContext /*= CLSCTX_ALL*/)
    {
    IXMLDOMDocument2 *p;
    HRESULT hr = CoCreateInstance(m_ClsId, pUnkOuter, dwClsContext, __uuidof(IXMLDOMDocument2), (LPVOID*)&p);
    if (hr != S_OK) AfxThrowComException(hr);
    return p;
    }
    
    1. 最简单的例子 - xml.rar(下载地址在文章开头)
    2. 这是从MSDN 2005中摘取的,我修改了一下代码。下载xml.rar后,你可以直接运行里面的buildme.bat来编译(必须安装了vc,并配置好了环境变量)。这个例子加载foo.xml文件后,调用IXMLDOMDocument2的get_xml返回xml文件内容。
      1. /*++

        Copyright (c) 2007 nsfocus information technology

        Module Name:

        enumxml.cpp

        Abstract:

        枚举foo,打印每个节点的值。

        Author:

        xuyibo (xuyibo) 2007-09-22

        Revision History:

        --*/

        #include
        #include
        #pragma comment(lib, "ole32.lib")
        #pragma comment(lib, "oleaut32.lib")

        IXMLDOMDocument2* LoadXML(WCHAR* pXML)
        {
            HRESULT hr;
            IXMLDOMDocument2* pXMLDoc = NULL;
            IXMLDOMParseError* pObjError = NULL;
            BSTR bstr = NULL;
            VARIANT_BOOL status;
            VARIANT vSrc;
           
            //
            // 创建一msxml 文档实例,返回IXMLDOMDocument2接口。
            hr = CoCreateInstance(CLSID_DOMDocument2,
                NULL,
                CLSCTX_INPROC_SERVER,
                __uuidof(IXMLDOMDocument2),
                (void**)&pXMLDoc);
            if (FAILED(hr)) {
                printf("Failed to CoCreate an instance of an XML DOM/n");
                printf("Error code: %x/n", hr);
                goto clean;
            }

        hr = pXMLDoc->put_async(VARIANT_FALSE);
            if (FAILED(hr)) {
                printf("Failed to set async property/n");
                goto clean;
            }

        hr = pXMLDoc->put_validateOnParse(VARIANT_FALSE);
            if (FAILED(hr)) {
                printf("Failed to set validateOnParse/n");
                goto clean;
            }

        hr = pXMLDoc->put_resolveExternals(VARIANT_FALSE);
            if (FAILED(hr)) {
                printf("Failed to disable resolving externals./n");
                goto clean;
            }

        VariantInit(&vSrc);
            V_BSTR(&vSrc) = SysAllocString(pXML);
            V_VT(&vSrc) = VT_BSTR;

        //
            // 读取foo.xml
            hr = pXMLDoc->load(vSrc, &status);

        if (status!=VARIANT_TRUE) {
                hr = pXMLDoc->get_parseError(&pObjError);
                hr = pObjError->get_reason(&bstr);
                printf("Failed to load DOM from books.xml. %S/n",bstr);
                goto clean;
            }
           
        clean:
            if (bstr)
                SysFreeString(bstr);
            if (&vSrc)
                VariantClear(&vSrc);
            if (pObjError)
                pObjError->Release();
           
            return pXMLDoc;
        }

        void Dump(BSTR pData)
        {
            char Buffer[512];
           
            WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, pData,
        -1, Buffer, sizeof(Buffer), NULL, NULL);
            puts(Buffer);
        }

        int main(int argc, char* argv[])
        {
            HRESULT hr;
            IXMLDOMDocument2* pXMLDoc = NULL;
            IXMLDOMNodeList* pNodeList = NULL;
            IXMLDOMNode* Node;
            IXMLDOMNamedNodeMap* NodeMap;
            IXMLDOMNode* IDNode;
            long I;
            long Length;
            BSTR BStr;
        BSTR BStrValue;

        //
            // First we must call CoInitialize.
            //
           
            CoInitialize(NULL);

        //
            // Load xml.
            //
           
            pXMLDoc = LoadXML(L"foo.xml");
            if (pXMLDoc == NULL) {
                return 1;
            }

        if (pXMLDoc->selectNodes(L"//root/item", &pNodeList) != S_OK) {
                return 1;
            }
           
            hr = pNodeList->get_length(&Length);
            if (FAILED(hr)) {
                return 1;
            }
           
            for (I = 0; I < Length; i++) {
                if (pNodeList->get_item(I, &Node) == S_OK) {
                   
                    //
                    // Dump text => Hello MSXML
                    //
                       
                    if (Node->get_text(&BStr) == S_OK) {
                        Dump(BStr);
                    }
                   
                    if (Node->get_attributes(&NodeMap) == S_OK) {
                        if (NodeMap->getNamedItem(L"id", &IDNode) == S_OK) {
                           
                            //
                            // Dump id => 1
                            //
                           
                            if (IDNode->get_text(&BStrValue) == S_OK) {
                                Dump(BStrValue);
                                puts("");
                                SysFreeString(BStrValue);
                            }
                            IDNode->Release();
                        }
                        NodeMap->Release();
                    }
                   
                    SysFreeString(BStr);
                    Node->Release();
                }  
            }
           
            pXMLDoc->Release();

        //
            // Finally we should call CoUninitialize
            //
           
            CoUninitialize();

        getchar();
            return 0;
        }

      1. 需要注意的地方

        1. 得到任何接口后,别忘记调用Release()来释放接口。

        今天我就在写完了xml的解析模块后,循环了1000次来测试,结果发现内存疯涨,后来发现是有一个IXMLDOMNode接口没有释放造成的。

        由于通常情况下,解析xml只执行1次,所以即使有资源泄漏也很难查找出来, 而且接口不同于HANDLE,泄漏后有工具可以检查出来。所以最好的方法就是通过循环来做压力测试。

        2. 通过FAILED宏严格检查函数执行结果。

        HRESULT hr;

        hr = pXMLDoc->load(vSrc, &status);
           if (FAILED(hr)) {
              // 错误处理
           }

        3. 最新的不一定就是最好的

        msxml都有6.0了,我用最老的是不是太落伍了?

        我不觉得是这样,msxml2 IE6中已自带,而且功能够用,如果用msxml6,我们首先必须将它放在我们的安装包中,还必须替微软注册它,然后才能使用,而且效率往往没有老版本的高。

        4. 效率考虑

        一般xml库在执行加载操作的时候会花费很多的时间。有时候,如果你要频繁的搜索某些东西,可以加载xml后,将IXMLDOMDocument2,或者更进一步的IXMLDOMNodeList接口保存起来。

        5. 别忘记SysFreeString

        当你使用get_text得到一个BSTR的时候,msxml另分配了一块返回值buffer,所以你必须调用SysFreeString来释放内存,这个在许多xml封装库中都没有注意到的。

        6.传入BSTR时,是否可以直接传WCHAR?

        如果是写商业产品,还是老老实实的用BSTR吧。估计要求效率的商业产品,没几个会选择MSXML。

        7. 内存中加载XML时,必须以UTF-8保存,而且读取后,必须跳过BOM值(如果存在的话)

        今天才遇到的问题。从加密文件中解密出UTF-8含BOM值的xml,然后必须跳过BOM值后转换为WCHAR,然后再转换为BSTR,然后再调用LoadXML才能成功加载(顶微软个肺)。主啊,愿我们XML文件务必一定小于100MB!感觉MSXML是为脚本语言开发的,C++用起来,隔靴搔痒。

      2. 相关文章

        最优雅的XML解析器TinyXML
        微软新的XML API - XmlLite
        expat教程

XML 解析器之一 :MSXML使用教程(转)相关推荐

  1. java xml解析器_Java XML解析器

    java xml解析器 Java XML parser is used to work with xml data. XML is widely used technology to transpor ...

  2. Android XML解析器– XMLPullParser

    Welcome to android xml parser example using XMLPullParser. We will have a sample XML file that we wi ...

  3. DOM4J——强大而易用的XML解析器,我们不只是有数据库

    DOM4J--强大而易用的XML解析器 DOM4J 一.DOM4J的导入使用 二.认识一些关键角色 三.快速开始 3.1创建一个XML 3.2读取XML节点(历遍和指定) 3.3规范输出 结尾 欢迎关 ...

  4. 简易XML解析器(C++)

    XML在web的应用是很广泛的,但对于普通c++程序员恐怕用得不多,xml灵活的格式使得一些设置文件描述变得很容易,但是应用他总是困难的,网络上XML解析器庞大的吓人,如果为了解析很简单的XML也要学 ...

  5. Java XML解析器

    使用Apache Xerces解析XML文档 一.技术概述 在用Java解析XML时候,一般都使用现成XML解析器来完成,自己编码解析是一件很棘手的问题,对程序员要求很高,一般也没有专业厂商或者开源组 ...

  6. TinyXML:一个优秀的C++ XML解析器

    读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...

  7. 先弄个XML解析器代码抄一抄 慢慢研究 O(∩_∩)O哈哈~

     出处:http://bbs.csdn.net/topics/390229172 已经自我放逐好几年了.打算去上班得了.在最后的自由日子里,做点有意义的事吧... 先来下载地址    http:/ ...

  8. Phinecos(洞庭散人) 专注于开源技术的研究与应用 TinyXML:一个优秀的C++ XML解析器

    读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...

  9. Python XML解析器– ElementTree

    Python XML parser provides us an easy way to read the XML file and extract useful data. Today we wil ...

最新文章

  1. 通过异或运算符加密解密 难度二星
  2. oracle所有的乱码解决方案
  3. DOS命令查看网络信息
  4. 重建道路(洛谷-P1272)
  5. Spring boot中使用aop详解
  6. STM32开关总中断
  7. Anaconda 安装步骤
  8. 教你阅读vue源码的正确姿势,看完就学废!
  9. 南方cass提取坐标生成表格_如何利用EXCEL随机生成测量点坐标导入南方CASS中计算土方量...
  10. Java生成桌面快捷方式(字节流生成)
  11. android答辩问题,安卓毕业设计答辩(流程、准备、模板及注意事项)
  12. 2020下半年新机最新消息_别买新机了!2020下半年手机居然这么强……
  13. 2021-11-12 Capturing Car-Following Behaviors by Deep Learning
  14. 计算机考研402,2021双非无项目科班402分上岸中科大-数学经验+复试全过程
  15. npm 安装出现 UNMET DEPENDENCY 的解决方案
  16. Java phantomjs 网页截图
  17. 【SVAC1】SVAC1与H.264支持特性比较
  18. win11升级后黑屏问题
  19. 梳理原型结构的方法小结
  20. Win10系统文件备份方法汇总

热门文章

  1. more命令的基本实现
  2. matlab 白平衡,白平衡算法
  3. 完美世界GameJam参加报告——《解字》游戏的设计与开发
  4. 断糖饮食和蜂蜜冲突吗?断糖减肥可以喝蜂蜜吗?
  5. FXS(le88266)工作原理介绍
  6. bcd转ascii码 流程图_BCD码到ASCII码转换实例
  7. 从边缘视角展望元宇宙
  8. 自建内网邮箱服务器(下)
  9. 养老服务机构引入电子签章推动养老合同在线签
  10. 第三个Sprint ------第十一天