`
isiqi
  • 浏览: 16545471 次
  • 性别: 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文档

      1. **XML解析器**:MSXML提供了几种不同的解析器,如MSXML2.DOMDocument、MSXML2.FreeThreadedDOMDocument等,它们能够加载XML文档并构建一个DOM(Document Object Model)树。DOM是一种将XML文档结构化为节点树的...

      XML解析MSXML解析

      总的来说,XML解析是软件开发中的基础技能,掌握MSXML解析器的使用对于在Windows环境下处理XML数据至关重要。理解DOM和SAX两种解析模式的优缺点,以及如何在MSXML中应用它们,是提升开发效率的关键。同时,不断学习...

      MSXML解析器

      1. DOM解析:MSXML中的DOM解析器允许开发者通过编程方式访问XML文档的结构,可以方便地创建、修改或查询XML文档的节点。DOM将整个XML文档加载到内存中,形成一个可遍历的对象树,便于进行复杂的查找和操作。 2. SAX...

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

      MSXML方法的XML解析器源码可以帮助开发者深入理解XML解析的内部工作原理,从而更好地利用这些工具进行XML处理。 DOM是一种将XML文档表示为树形结构的模型,允许开发者通过节点操作来访问和修改XML数据。在MSXML中,...

      XML.rar_c xml_msxml_msxml pudn_msxml xml_xml 解析

      本示例中,"DOM-MSXML实现解析xml文件"着重介绍了如何利用MSXML库的DOM解析器来处理XML。具体步骤如下: 1. **初始化解析器**:首先,需要实例化一个IXMLDOMDocument对象,这可以通过CoCreateInstance函数完成,...

      xml解析器(解决XML错误)

      XML(eXtensible Markup ...这个压缩包提供的MSXML组件和安全更新,旨在提供一个稳定、安全的环境来处理XML文档,无论你是XML初学者还是经验丰富的开发者,都应该掌握XML解析器的使用,以提高工作效率和代码质量。

      MSXML解析开发包

      MSXML,全称为Microsoft XML Core Services,是由微软公司开发的一款XML解析器,它允许程序员和Web开发者处理、创建和查询XML文档。XML(eXtensible Markup Language)是一种标记语言,广泛用于数据交换、存储和表示...

      利用MSXML解析XML文档

      其中,DOM 解析器允许开发者以面向对象的方式处理 XML 文档,而 SAX 解析器则更适用于处理大型文档,因为它不需要一次性加载整个文档到内存。 使用 MSXML 解析 XML 文档的步骤通常包括以下几步: 1. 引入 MSXML 库...

      XML解析器VB

      在VB中,我们可以使用内置的MSXML库(Microsoft XML库)或者.NET Framework提供的System.Xml命名空间来创建XML解析器。 1. **MSXML库**:这是Microsoft提供的一套COM组件,包括MSXML2.DOMDocument、MSXML2.XMLHTTP...

      js的XML解析器 可以解析XMl文件和XML字符串

      JavaScript中的XML解析器是用于处理XML数据的关键工具,它允许开发者在浏览器环境中解析XML文档或者XML字符串,从而在Web应用中有效地使用这些数据。XML(eXtensible Markup Language)是一种结构化数据语言,常用于...

      XML解析器安装包

      对于Windows系统,MSXML(Microsoft XML Core Services)提供了一个内置的XML解析器,其中msxml4.dll是MSXML 4.0版本的动态链接库文件,包含了许多与XML处理相关的接口和类。 在安装“XML解析器安装包”时,通常会...

      MSXML 4.0 SP2 Parser and SDK

      5. **SAX(Simple API for XML)接口**:除了DOM,MSXML还支持SAX解析器,它是一种事件驱动的解析方式,适用于处理大型XML文档,因为它不需要一次性加载整个文档到内存中。 6. **XPath和XSLT支持**:MSXML 4.0 SP2...

      xml 解析器,xml 解析器,xml 解析器,

      在Windows环境中,MSXML(Microsoft XML Core Services)是一个常用的XML解析器库,提供了对DOM、SAX和XPath的支持。其中,msxml6.msi文件很可能是MSXML的一个安装包,用于在系统上安装或更新这个组件。安装MSXML后...

      XML程序软件MSXML5组件

      1. **XML解析器**:MSXML5的解析器负责将XML文本转换为内存中的数据结构,可以进行验证或非验证解析。验证解析会检查XML文档是否符合指定的DTD(Document Type Definition)或XML Schema,确保数据的合法性。 2. **...

      xml_分析器.zip_XML VC_XML 解析_XML解析_vc解析xml_xml解析器

      在VC环境中开发XML解析器时,开发者通常会利用标准库(如Windows SDK中的MSXML或开源库如TinyXML、pugixml)或自行实现解析逻辑。通过分析`ce_xml.cpp`,我们可以深入理解XML解析器的工作原理,学习如何处理XML的开...

      MSXML 4.0 和MSXML 6.0解析器

      在提供的信息中,我们关注的是MSXML的4.0和6.0两个版本,这两个版本在XML解析器领域都有着重要的地位,尤其对于初学者来说,它们是理解和实践XML技术的基础工具。 XML(eXtensible Markup Language)是一种标记语言...

      VC6 XML解析器

      **VC6 XML解析器** XML(eXtensible Markup Language)是一种用于标记数据的语言,它在软件开发领域,尤其是在Web应用程序和数据交换中扮演着重要角色。VC++ 6.0,是Microsoft Visual C++的一个早期版本,它提供了...

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

      XML(eXtensible Markup Language)是一种用于标记数据的语言,广泛应用在数据交换、配置文件以及软件的本地化等领域。...这个过程涉及了XML解析、COM组件的使用、DOM树遍历以及在对话框中显示结果等多方面的技术。

    Global site tag (gtag.js) - Google Analytics