最近一阵发飚,猛地花了两天的时间来研究如何使用MSXML来转换XSLT/XML文档,目前也是小有所成吧。这方面的资料网上也比较少,为此也是花了不少功夫。其中感觉对自己最大的帮助莫过于MSDN了,几乎80%的信息来源都出于此。然后就是在网上找到了一篇英文的文章来介绍此的用法了。所以,对于初学者的忠告还是多研究MSDN,这里面的实例以及对各个接口的介绍要比网上那些乱七八糟的介绍要好多了,这里会更系统一些。当然,有了我这篇文章的话,你的入门就完全不用愁了(呵呵,自夸下)。
首先,在读这篇文章之前,我是默认你已经对如何用MSXML来解析处理XML文档有了一定的了解了,如果不会的话,请参照我前几篇文章关于MSXML解析XML的讲述。下面开始进入正题:
转换XSL/XML有两种方法,其中一种就是采用微软提供的旧方法:
IXMLDOMNode::transformNode()或是IXMLDOMNode::transformNodeToObject()
另外一种就是采用微软提供的IXSLTemplate处理。
先来介绍第一种方法吧:
法一::IXMLDOMNode::transformNode()
第一步:初始化
第二部:加载文档
第三步:执行转换
第四步:释放内存
由于该方法较为简单,各个函数的功能请参照MSDN,在此就不再进行赘述了。下面就开始细述我们的重点了-IXSLTemplate。
方法二:IXSLTemplate
处理XML和XSL可以分为如下几个步骤:
1) 初始化COM组件
2) 加载XML文档
3) 初始化XSLT处理器
4) 执行转换
5) 将转换结果输出到STDOUT
首先,创建VC工程,然后导入DOM组件,具体也不细述。
下面就开始了执行处理XSLT和XML了。
首先我们需要创建两个IXMLDOMDocument接口,其中分别为XML文档和XSL文档。然后在创建IXSLTemplate接口,通过该接口再创建IXSLProcessor。IStream将会用来存储转换的结果。
在此处,使用FreeThreadedDOMDocument对象为XMLDocument接口来创建XSL模板是非常重要的。每个以Ptr为后缀的接口意思是其为一个封装了一些给定的接口的一个小巧的指针。使用它们会使代码变得短小并简单易读。
第一步:声明及初始化
如下代码为各个接口变量的声明:
第二步:创建接口
第三步:加载各个文档:
其中_bstr_t是用来方便将ANSI字符串转换到BSTR字符串。
第四步:创建处理器Processor并加载样式表xsl到模板中
加载完成XML文档之后,下面就开始初始化template了,同时其也可以创建处理器(Processor)。在微软增加template功能之前,每个XSLT样式表必须通过transformNode或是transformNodeToObject方法来进行编译并执行转换。现在XSLTemplate对象能够被用来存放一个XSLT样式表并用它来转换多个XML文档,同时其功能也比以前要强大的多。XSLProcessor对象应该在每次转换时都要被重新创建。如下代码:
第五步:导入XML文档作为Processor的输入,执行转换并读取输出
在该步骤中,参考到网上的另外一种为处理器Processor添加输出流(该方法我测试一直没成功,输出的流为空,原因也未查出,但还是介绍给大家吧)。
现在我们需要开始配置我们的转换了。我们需要一个缓冲器来存放我们的输出。这用过创建一个Stream对象来实现,并且在IStream类型中的一个变量来存储其接口。当转换器需要更多的空间来存储它的输出时,该流也会自动的进行扩展。但要注意的是,存储在该流中的字符串并不是ANSI字符串,所以其并不会以NULL作为结尾。在下面的代码中为需要转换的XML文档分配了一个处理器;同样也给XSL传入了一个变量,其值为35,如果你的XSL文档中不需要传输参数,此句也不需要.
// prepare Stream object to store results of transformation,
// and set processor output to it
CreateStreamOnHGlobal(NULL,TRUE,&pOutStream);
pProcessor->put_output(_variant_t(pOutStream));
// attach to processor XML file we want to transform,
// add one parameter, maxprice, with a value of 35, and
// do the transformation
vResult = pProcessor->put_input(_variant_t((IUnknown*)pXml));
pProcessor->addParameter(_bstr_t("maxprice"), _variant_t("35"),_bstr_t(""));
pProcessor->transform();
如果转换成功,输出能够通过锁定的流来读取并获得其开始的指针。在此之前,将在流的末尾添入NULL,这样以后输出到控制台将会变得容易些。最后,还需要释放这些指针并释放COM组件。
//get results of transformation and print them to stdout
HGLOBAL hg = NULL;
pOutStream->Write((void const*)"/0",1,0);
GetHGlobalFromStream(pOutStream,&hg);
output = GlobalLock(hg);
printf("%s",(const char*)output);
GlobalUnlock(hg);
//release before CoUninitialize()
pXml.Release();
pXslt.Release();
pTemplate.Release();
pProcessor.Release();
CoUninitialize();
至此,我们的方法已经介绍的差不多了。当然,其中接口提供更多的功能,在此就需要自己去慢慢研究MSDN了,入门到此也就够了。
另外,本人参考的网上的外文博客文章地址如下:
http://www.codeguru.com/cpp/data/data-misc/xml/article.php/c4565/
大家可以自行参考。