`
isiqi
  • 浏览: 16004800 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

XML 解析器之一 :MSXML使用教程(转)

阅读更多
  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教程

    分享到:
    评论

    相关推荐

      使用msxml方法 的xml解析器 源码

      使用msxml方法 的xml解析器 源码,个人觉得还不错。

      msxml ,微软的xml语言解析器

      微软的xml语言解析器

      MSXML解析XML文档

      微软提供了一个XML语法解析器,即一个叫做MSXML.DLL的动态链接库,实际上它是一个COM(Component Object Model)对象库,里面封装了进行XML解析时所需要的所有对象。因为COM是一种以二进制格式出现的和语言无关的可...

      解析XML文档 实现树结构实例

      开发环境为VC,基于对话框,用msxml组件解析XML文档,运用递归循环的方法实现树结构,支持中文,可以运行的一个实例。

      Pb_xml.zip_icecza_pb web_pb 6.5 安装使用_pb解析XML_xml

      当您打开工作表, XML解析器: XML解析器 加载文件:在这里,您可以只加载一个XML文件,并看到它解析在TreeView 。 pb_list_style :档案emplyees.xml将解析和转化利用pb_list_style.xsl ,由此产生的HTML中...

      MSXML 4.0 和MSXML 6.0解析器

      XML 解析器,两个版本,任你选择.XML初学者的必备工具

      msxml(xml语言解析器)v4.0sp3parser中文官方安装免费版

      msxml是由微软推出的xml语言解析器,主要用来解析所有由微软软件生成的xml标准文档,本款是msxml4.0 sp3版本,也是目前msxml4.0版本中最完善的版本。由于msxml各个版本之间是互相独立的,所以一般用户都需要同时安装...

      MSXML解析开发包

      msxml微软的xml语言解析器,用来解释xml语言的。包含 SDK 软件开发套件。

      XML解析器安装包

      安装了这个之后在MFC中#import &lt;msxml4.dll&gt;就可以在MFC中调用IXMLDOMDocumentPtr类的函数

      MSXML6.0 官方安装版

      微软的xml语言解析器,用来解释xml语言的。就好像html文本下载到本地,浏览器会检查html的语法,解释html文本然后显示出来一样。要使用xml文件就一定要用到xml parser。不过不仅仅微软有,像ibm,sun都有自己的xml ...

      Microsoft® XML Core Services (MSXML) 5.0 参考手册

      Microsoft® XML Core Services (MSXML) 5.0 ,微软 XML解析器与架构的参考手册,英文版。

      VC使用Cmarkup生成、解析xml资料

      MSXML:CMarkupMSXML类用EDOM方法包装了微软的XML服务。MSXML编译选项用来演示这个类。 UNICODE(统一字符编码标准):对于WindowsNT和WindowsCE平台能够被编译成UNICODE,在WindowsNT UNICODE下,XML文档是流到UTF-...

      msxml(xml校验工具)

      MSXML 是一款微软的 xml 语言解析器,它的全名是:「Microsoft XML Core Services」,主要是用来执行或开发经由 XML 所设计的最新...

      利用MSXML解析XML文档 (2009年)

      本丈通过分析微软公司的MSXML的XMI.语法解析器(即MSXML.DLL的动态链接库)的工作原理,利用这个COM对象库中提供的时象,实现了对XML文档的解析,并用VC++加以实现。

      MSXML6(分析程序) v6.0 官方安装版.zip

      微软的xml语言解析器,用来解释xml语言的。就好像html文本下载到本地,浏览器会检查html的语法,解释html文本然后显示出来一样。要使用xml文件就一定要用到xml parser。不过不仅仅微软有,像ibm,sun都有自己的xml ...

      msxml.msi下载

      msxml.msi下载,提示xml出错时安装即可。xml解析器

      如何用vc创建和读取xml文件

      MSXML解析器允许你装载和创建一个文档,收集文档的错误信息,得到和操作文档中的所有的信息和结构,并把文档保存在一个XML文件中。DOM提供给用户一个接口来装载、到达和操作并序列化XML文档。DOM提供了对存储在内存...

      xml入门经典-part3(中文版)

      2.3.4 标记:一个简单的例子 2.3.5 文档元素 2.3.6 子元素 2.3.7 元素嵌套 2.3.8 字符串 2.4 字符数据 2.5 属性 2.5.1 特殊属性 2.5.2 空白 2.5.3 行尾的处理 2.6 字符引用和实体引用 2.6.1 字符引用 ...

      XML高级编程pdf

      2.3.4 标记:一个简单的例子 2.3.5 文档元素 2.3.6 子元素 2.3.7 元素嵌套 2.3.8 字符串 2.4 字符数据 2.5 属性 2.5.1 特殊属性 2.5.2 空白 2.5.3 行尾的处理 2.6 字符引用和实体引用 2.6.1 字符引用 ...

    Global site tag (gtag.js) - Google Analytics