从IXMLDOMDocument2中获取指定编码(如UTF-8)格式的数据

  今天,重构项目的主体框架编码进入收尾阶段。只差XML文本数据的发送这个函数了。
  先前项目XML文本发送,对编码的处理是采用自写函数进行转换。由于想写一个比较灵活的底层框架,所以决定放弃先前的方法。
  首先建立一个测试程序,代码如下:
// XMLTest.cpp : 定义控制台应用程序的入口点。    
//    
#include  "stdafx.h"    
#include  <atlbase.h>    
#include  <atlcom.h>    
#import   "msxml2.dll"        
using     namespace     MSXML2;    
using     namespace     std;    
#define XML_IXMLDOMNodePtr                  MSXML2::IXMLDOMNodePtr    
#define XML_IXMLDOMElementPtr              MSXML2::IXMLDOMElementPtr    
#define XML_DOMDocument                      MSXML2::DOMDocument    
typedef CComQIPtr<IXMLDOMDocument2>   CXMLDomDocument;    
void xmlTest(void)    
{    
        CXMLDomDocument                        spTestXML;    
        spTestXML.CoCreateInstance(__uuidof(XML_DOMDocument));    
        spTestXML->appendChild(spTestXML->createProcessingInstruction(_T( "xml"), _T( "version='1.0' encoding='UTF-8'")));    
        XML_IXMLDOMElementPtr spElement = spTestXML->createElement(_T( "test"));    
        spElement->setAttribute(_T( "name"), _T( "中华人民共和国"));    
        spTestXML->documentElement = spElement;    
        cout << spTestXML->xml << endl;    
}    
int _tmain(int argc, _TCHAR* argv[])    
{    
        CoInitialize( NULL);    
        xmlTest();    
        CoUninitialize();    
        cin. get();    
        return 0;    
}
  输出的结果很明显,但并不是我想要的结果。我要的是输出UTF-8格式的数据,而不是可以在屏幕上直接显示的GB2312格式。
  直接取xml属性值并不能达到要求,于是想看看保存到文件的结果如何。就在xmlTest函数最后加上一行代码:spTestXML->save(_T("d:\\bbb.xml"));运行后,用命令行去查看结果,如图:
1
正是想要的结果。
  要把此数据通过SOCKET发送出去,虽然可以在发送前把数据保存到一个临时文件中,再读取文件进行发送。这样的方法只能在实在行不通的时候才采用,其原因不言自明。
  还是老方法,首先查看IXMLDOMDocument2接口代码。在看到IXMLDOMDocument接口的save函数时,发现了传入的参数并不是简单的字符串类型,而是一个VARIANT类型的数据。这时想到的第一件事就是这个函数可以传其它类型的数据,比如接口等。
  于是想试试传IStream,就添加了一个类,实现IStream接口。代码如下:
class ATL_NO_VTABLE CTestStream:    
         public CComObjectRootEx<CComSingleThreadModel>,    
         public IStream    
{    
public:    
BEGIN_COM_MAP(CTestStream)    
        COM_INTERFACE_ENTRY(IStream)    
END_COM_MAP()    
public:    
        STDMETHOD(Read)(    
                /* [length_is][size_is][out] */ void *pv,    
                /* [ in] */ ULONG cb,    
                /* [out] */ ULONG *pcbRead) {return S_OK;}    
        STDMETHOD(Write)(    
                /* [size_is][ in] */ const void *pv,    
                /* [ in] */ ULONG cb,    
                /* [out] */ ULONG *pcbWritten) {return S_OK;}    
        STDMETHOD(Seek)(    
                /* [ in] */ LARGE_INTEGER dlibMove,    
                /* [ in] */ DWORD dwOrigin,    
                /* [out] */ ULARGE_INTEGER *plibNewPosition) {return S_OK;}    
        STDMETHOD(SetSize)(    
                /* [ in] */ ULARGE_INTEGER libNewSize) {return S_OK;}    
        STDMETHOD(CopyTo)(    
                /* [unique][ in] */ IStream *pstm,    
                /* [ in] */ ULARGE_INTEGER cb,    
                /* [out] */ ULARGE_INTEGER *pcbRead,    
                /* [out] */ ULARGE_INTEGER *pcbWritten) {return S_OK;}    
        STDMETHOD(Commit)(    
                /* [ in] */ DWORD grfCommitFlags) {return S_OK;}    
        STDMETHOD(Revert)( void) {return S_OK;}    
        STDMETHOD(LockRegion)(    
                /* [ in] */ ULARGE_INTEGER libOffset,    
                /* [ in] */ ULARGE_INTEGER cb,    
                /* [ in] */ DWORD dwLockType) {return S_OK;}    
        STDMETHOD(UnlockRegion)(    
                /* [ in] */ ULARGE_INTEGER libOffset,    
                /* [ in] */ ULARGE_INTEGER cb,    
                /* [ in] */ DWORD dwLockType) {return S_OK;}    
        STDMETHOD(Stat)(    
                /* [out] */ STATSTG *pstatstg,    
                /* [ in] */ DWORD grfStatFlag) {return S_OK;}    
        STDMETHOD(Clone)(    
                /* [out] */ IStream **ppstm) {return S_OK;}    
};
  这个类所有函数只是简单的实现了IStream接口,返回S_OK值。现在将spTestXML->save(_T("d:\\bbb.xml"));这行代码改为:spTestXML->save(_variant_t(new CComObjectNoLock<CTestStream>()));并在每个函数内设置一个断点。进行调试,程序在Write函数的断点暂停了,监视此函数的参数,发现pv参数的值正是自己想要的数据,这说明此方法完全可行。于是对此函数做了改动以输出结果,代码:CString st((char*)pv, cb);cout << st << endl;return S_OK;运行后在屏幕上输出的正是自己想要的结果。
  本来在这里算是完成,突然想到整个IStream接口中,save过程只调用了Write函数。并且此函数是从ISequentialStream接口派生来的,于是想到是否可以直接用ISequentialStream,经过测试完全可行。
  代码就没贴了,做为附件传上来(代码在VS 2003中测试通过)。程序运行结果图:
2
  同样,如果要输出UTF-16等其它编码格式,只要将spTestXML->appendChild(spTestXML->createProcessingInstruction(_T("xml"), _T("version='1.0' encoding='UTF-8'")));做一下改动并在Write函数中做相应的处理即可。

你可能感兴趣的:(xml,utf-8,休闲,IXMLDOMDocument)