zoukankan      html  css  js  c++  java
  • 在VC6中使用MSXML 4.0 DOM处理XML文档


    在VC6中使用MSXML 4.0 DOM处理XML文档


        本文简要讨论XML/DOM和MSXML,并示例如何在VC6.0中使用MSXML 4.0 DOM处理XML文档。
        作者:tyc611.cublog.cn,2007-09-21

    1. DOM与XML

        DOM是Document Object Model的缩写,提供了与XML交互的标准编程模型:(1)提供了标准方法在程序中创建、遍历或者更新XML文档内容。(2)提供了一组核心的与供应商和语言无关的应用程序编程接口(API),可满足与XML交互的大部分需求。因此,DOM APIs成为应用程序和XML文档之间互通的桥梁。

        W3C(World Wide Web Consortium)DOM Level 1规范定义了两组DOM编程接口:
        (1)基本接口:W3C基本接口定义了用来在应用程序中操纵XML文档的接口;
        (2)扩展接口:W3C扩展接口定义了一些方便开发者的接口。

        所有XML处理程序必须支持Unicode字符编码的两种形式:UTF-8和UTF-16。XML Parser可以读取使用ISO-8859-1、Big-5或者Shift-JIS编码的文档,并在加载文档时将它们自动转换为Unicode。

        如果XML文档使用的字符编码不是UTF-8(8-bit ASCII文本也是可接受的UTF-8)或者UTF-16,那么它必须在XML声明中提供字符编码声明,否则XML Parser可能会出错。当然,即使对字符编码进行了声明,Parser也可能不能够处理(不支持该编码),但能够正确地给出提示信息。(由于XML声明是使用基本的ASCII文本书写的,Parser能够正确地读出它的内容。)

    2. MSXML 4.0简介

        MSXML(Microsoft XML Core Services)是Microsoft提供的用于处理XML文档的COM库。MSXML DOM不仅实现了W3C DOM Level 1规范定义的基本接口和扩展接口,还提供了额外的方法来支持XSL Transformation(XSLT)、XPath、名字空间和数据类型。MSXML除了支持规范所要求的字符编码外,还支持更多的字符编码格式,而在内部使用Unicode UCS-2字符编码处理XML文档中的所有文本。

        本文以Visual C++ 6.0为开发环境,介绍MSXML4.0 SDK中DOM的使用。另外,MSXML中的SAX也比较常用。

    2.1. MSXML DOM

        MSXML DOM是本文介绍的重点,它提供了丰富的接口方便在程序中操作XML文档。DOM在内存中提供了XML文档的完整表示,允许对整个文档内容的随机访问。 DOM允许应用程序依赖于MSXML Parser提供的逻辑结构来处理基于XML的信息。其工作流程和原理如下图所示(源自MSXML 4.0 SDK):

     

        当MSXML Parser把一个XML文档加载进DOM时,它从头到尾读入整个XML文档,并构建内在逻辑树结构。文档本身被认为是包含其它所有节点的单个节点,例如,它包含根元素(Root Element),而根元素则包含文档中所有的元素、属性和文本节点。

        MSXML DOM树中每一个节点都有特定的类型(如元素、属性、文本),也有指向父节点和子节点的成员。其中,属性节点是一个特殊的节点,它不是子节点,是元素的属性。

    2.2. MSXML SAX2

        有时,使用SAX(Simple API for XML)来解决XML应用可能是一个更好的选择。DOM方式允许开发者利用MSXML维护的DOM树,而不用自己来管理。但有时,开发者需要更高的效率时,可能只需要读入XML文档,而在程序内部构造数据结构来管理XML文档信息,这时就可以选择SAX方式。下图是MSXML SAX2的工作流程和原理图(源自MSXML 4.0 SDK):

    3. 安装MSXML 4.0 SDK

        早期的MSXML版本,特别是MSXML 2.5和MSXML 3.0,借助于xmlinst.exe工具,可以以替换模式进行安装。在替换模式下,新安装的MSXML版本替换旧版本,从而变成缺省的XML Parser。当你在程序中使用版本无关的CLSID和ProgID时,缺省的XML Parser就被调用。这常常引起旧程序的兼容性问题。基于这个原因,MSXML 4.0只能以Side-by-side模式进行安装。Xmlinst.exe工具在MSXML 4.0中不再提供,也不适用于MSXML 4.0。

        MSXML 4.0 SDK(Microsoft XML Core Services 4.0 Software Development Ket)是以side-by-side模式安装在你的机器上的。这种模式有助于保护那些使用msxml.dll、msxml2.dll,或者 msxml3.dll的应用程序,使其不受干扰,仍可照常使用。Side-by-side模式允许你决定使用哪个版本的Parser来为你工作,这可在你的代码中指定。
    从Microsoft XML Download Center下载回安装程序,安装程序将在你的机器上安装三个文件:msxml4.dll、msxml4a.dll和msxml4r.dll,并对msxml4.dll进行注册。

        或者,你也可以手动安装MSXML,如果你乐意的话。首先,拷贝上面的三个dll文件到机器的系统目录($sysRoot\system32),一般是 C:\WINDOWS\system32;然后,运行cmd,执行命令:(1) cd C:\WINDOWS\system32  (2) regsvr32 msxml4.dll。
    在安装MSXML 4.0 SDK后,应用程序必须使用版本相关的CLSID和ProgID来显式地实例化Parser,这确保你的应用程序的稳定性。

    4. 使用MSXML DOM

        本节介绍在VC6.0中使用MSXML DOM处理XML文档。下面的示例中将动态生成一个XML文档,并对文档进行查询。

    4.1. 导入MSXML

        首先,需要导入MSXML头文件和库到VC6.0工程中。有两种导入方式:
        (1)自动方式,在源代码中添加如下两行程序即可:
             #import <msxml4.dll>
             using namespace MSXML2;
        (2)手动方式(有存在的理由么?呵呵)
            a)找到MSXML 4.0 SDK的安装目录,去发现两个子目录inc和lib;
            b)在VC选项中,将MSXML 4.0下inc和lib子目录添加到默认的头文件和库文件搜索路径中;
            c)在使用MSXML的源文件中包含头文件<msxml2.h>;
            d)在工程设置中将msxml2.lib添加到要链接的库中。

        以自动方式导入MSXML,会在你的工程目录下(或者Debug/Release下)生成两个头文件msxml4.tlh和msxml4.tli(前者为头文件声明,后者为内联函数定义文件)。

    4.2. XML样例文档

        后面的程序中将动态生成如下XML文档,然后对该文档进行查询。

    <?xml version="1.0" encoding="utf-8"?>

    <!--Sample XML file created using XML DOM object.-->

    <request>

      <identification>

        <userName>tyc</userName>

        <password>pwd</password>

      </identification>

     

      <commandLines count="2" reply="no" immediate="yes">

        <command num="1">

          <type>backup</type>

          <dbName>db1359</dbName>

        </command>

        <command num="2">

          <type>save</type>

          <data><![CDATA[这里是XML文档的CDATA数据段...]]></data>

        </command>

      </commandLines>

    </request>

    4.3. 用到的COM技术

        与其它COM技术一样,MSXML也使用引用计数来管理DOM对象的生存期。当使用MSXML中的COM裸接口指针时,程序员必须负责处理该指针的引用计数:调用AddRef增加引用计数;调用Release减少引用计数。

        例如,当调用IXMLDOMDocument::createNode、IXMLDOMNode::appendChild或者 CoCreateInstance创建或者获取对象时,对象的引用计数已经在函数返回前增加了,而你却有责任在使用完这些指针后调用Release释放对象。如果你复制一个已存在对象的引用,你必须调用AddRef增加相应的引用计数。

    4.4. MSXML DOM中裸指针与智能指针的用法区别

        MSXML中成员函数有两类,一类成员函数的返回值是通过参数返回的,而函数本身返回HRESULT作为操作成功与否的标识,如果函数返回的值(通过参数)是指针,那么该指针是裸指针,这里把这类用法称为裸用法,这种函数称为裸函数;另一类成员函数是对前面的裸函数的简单封装形式,把裸函数的返回值作为真正的返回值返回,如果是返回指针,则指针不再是裸指针,而是经过封装的智能指针。一般前类函数的函数名中有下划线,而后者没有。你可以在生成的 msxml4.tli文件中看到这种封装。

    4.5. 源程序

        不多说了,看代码吧。(注:本来想贴上所有代码的,但系统字数限制,只好删除了两个实现函数,请看文后的源程序打包文件)

    #include <iostream>

    #include <string>

    #include <cassert>

     

    using namespace std;

     

    #import <msxml4.dll>

    using namespace MSXML2;

     

    bool generateXMLSampleFile(const string &path);

    bool queryXMLSampleFile(const string &path);

     

    int main()

    {

        // 初始化COM

        CoInitialize(NULL);

     

        // 创建XML文件及其内容

        if (!generateXMLSampleFile("sample.xml"))

            cout << "Failed" << endl;

     

        // 加载刚生成的XML文件,将其输出到标准输出中予以显示

        IXMLDOMDocument2Ptr pXMLDom;

        HRESULT hr = pXMLDom.CreateInstance(__uuidof(DOMDocument40));

        if (FAILED(hr)) {

            cout << "Failed to instantiate DOMDocument40 class!" << endl;

            return -1;

        }

       

        if (pXMLDom->load("sample.xml") != VARIANT_TRUE) {

            cout << "Failed load xml data from file: " <<

                static_cast<char*>(pXMLDom->parseError->Getreason()) << endl;

            return -1;

        }

     

        // 下面输出XML文件内容,但奇怪的是文件头中没有编码的部分!

        cout << static_cast<char*>(pXMLDom->xml) << endl;

     

        pXMLDom.Release();  // 注意,不能用pXMLDom->Release()这种形式!

     

        // 对刚生成的XML文件进行查询

        cout << "---------------------------------------" << endl;

        cout << "Start query..." << endl;

        queryXMLSampleFile("sample.xml");

       

        CoUninitialize();

     

        return 0;

    }

        补充下,如果是遍历一个未知XML文档,就需要使用IXMLDOMDocumentPtr的documentElement获得根元素,使用 IXMLDOMNodePtr的firstChild、nextSibling成员获得一个节点的所有子节点;使用IXMLDOMNodePtr的 nodeType成员来判断节点类型(元素、属性、文本,等等),使用text成员得到文本值,使用nodeName成员得到节点名。还可以使用 IXMLDOMDocumentPtr、IXMLDOMNodePtr等的xml成员获得相应的xml字符串。另详细的资料请参考MSXML 4.0 SDK文档。

        另外,在程序中动态创建的text节点的text值的数据量大小是有限的,在我的机器上测试发现(默认VC配置),使用256K的数据还正常,但使用512K的数据时就Stack Overflow了。但是,加载XML文档时是没有问题的,其数据量并不受此限制。

        最后,在你使用MSXML DOM时,请清醒地认识到它在内部是一颗树的表示,任何数据都是以节点形式存在的。That’s all!

    附上源程序文件如下:

    文件: MSXML_TEST.rar
    大小: 3KB
    下载: 下载
  • 相关阅读:
    HTTP 协议(一)之基本概念入门
    聊聊 PHP 私有组件以及如何创建自己的 PHP 组件 (转)
    组件、框架、Packagist、Composer
    laravel 资源篇
    190318 面试题记录
    Http 协议
    python中全局变量的修改
    python lamba表达式
    python 按位置关系输出矩阵元素
    python 三目运算
  • 原文地址:https://www.cnblogs.com/dongzhiquan/p/1994937.html
Copyright © 2011-2022 走看看