
DOM是以COM形式提供的,VC++里调用DOM可以分3种方法:
1、MFC里用CComPtr调用
2、SDK里直接调用DOM接口
3、SDK里用智能指针调用
这3种方法本质上是一样的,区别只不过在于需要编码的多少而已,用CComPtr可以极大的简化代码,下面是几个例子。
例子stocks.xml:
<?xml version="1.0" encoding="utf-8"?>
<root>
<node1>text1</node1>
<node2>
<childnode1 attrib1="value1" attrib2="value2"/>
<childnode2 attrib1="value1" attrib2="value2">childtext1</childnode2>
</node2>
</root>
这个例子应该包含了XML最常见的特征了吧?
MFC
MFC里可以直接使用DOM,不需要手动添加额外的头文件,只需要在CWinApp::InitInstance()里调用CoInitialize(NULL)初始化COM,在CWinApp::ExitInstance里调用CoUninitialize()释放COM就行了。
//读取XML
CComPtr<IXMLDOMDocument>spDoc//DOM
spDoc.CoCreateInstance(CLSID_DOMDocument)
VARIANT_BOOL vb
spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb)//加载XML文件
CComPtr<IXMLDOMElement>spRootEle
spDoc->get_documentElement(&spRootEle)//根节点
CComPtr<IXMLDOMNodeList>spNodeList
spRootEle->get_childNodes(&spNodeList)//子节点列表
long nLen
spNodeList->get_length(&nLen)//子节点数
for (long i = 0i != nLen++i) //遍历子节点
{
CComPtr<IXMLDOMNode>spNode
spNodeList->get_item(i, &spNode)
ProcessNode(spNode)//节点处理函数
}
//写入XML
CComPtr<IXMLDOMNode>spNode
spRootEle->selectSingleNode(OLESTR("/root/node1"), &spNode)
spNode->put_text(OLESTR("newText"))//写入text
spRootEle->selectSingleNode(OLESTR("/root/node2/childnode1/@attrib1"), &spNode)
spNode->put_nodeValue(CComVariant(OLESTR("newValue")))//写入value
CComPtr<IXMLDOMNode>spNewNode
spDoc->createNode(CComVariant(NODE_ELEMENT), OLESTR("childnode3"), OLESTR(""), &spNewNode)//创建新节点
spRootEle->selectSingleNode(OLESTR("/root/node2"), &spNode)
spNode->appendChild(spNewNode, &spNewNode)//将新节点加为node2的子节点
spNewNode->put_text(OLESTR("childtext2"))//写入新节点text
CComQIPtr<IXMLDOMElement>spEle = spNewNode//注意这里使用CComQIPtr
spEle->setAttribute(OLESTR("attrib1"), CComVariant(OLESTR("value1")))//给新节点添加属性
spDoc->save(CComVariant(OLESTR("stocks.xml")))
//节点处理函数
void ProcessNode(CComPtr<IXMLDOMNode>&spNode)
{
CComBSTR bsNodeName
spNode->get_nodeName(&bsNodeName)//节点名
AfxMessageBox(COLE2CT(bsNodeName))
CComVariant varVal
spNode->get_nodeValue(&varVal)//节点值
AfxMessageBox(COLE2CT(varVal.bstrVal))
DOMNodeType eNodeType
spNode->get_nodeType(&eNodeType)
if (eNodeType == NODE_ELEMENT) //只有NODE_ELEMENT类型才能包含有属性和子节点
{
//递归遍历节点属性
CComPtr<IXMLDOMNamedNodeMap>spNameNodeMap
spNode->get_attributes(&spNameNodeMap)
long nLength
spNameNodeMap->get_length(&nLength)
for (long i = 0i != nLength++i)
{
CComPtr<IXMLDOMNode>spNodeAttrib//注意属性也是一个IXMLDOMNode
spNameNodeMap->get_item(i, &spNodeAttrib)
ProcessNode(spNodeAttrib)
}
//递归遍历子节点
CComPtr<IXMLDOMNodeList>spNodeList
spNode->get_childNodes(&spNodeList)
spNodeList->get_length(&nLength)
for (long i = 0i != nLength++i)
{
CComPtr<IXMLDOMNode>spChildNode
spNodeList->get_item(i, &spChildNode)
ProcessNode(spChildNode)
}
}
}
对于<tag>text</tag>这样的节点,get_nodeValue会得到空,要得到"text"的话可以遍历子节点(只有一个子节点,它的nodeName为"#text",nodeType为NODE_TEXT,nodeValue就是"text");也可以用get_text直接得到"text",但是对于这样的节点<tag>text<childtag>childtext</childtag></tag>,get_text会同时得到"text"和"childtext",不过这样的节点应该是不允许的。
DOM里使用的字符串(BSTR)都是OLESTR类型,默认情况下OLESTR是Unicode字符,MFC里可以用COLE2CT把LPCOLESTR转换为LPCTSTR。
对于自己定义的XML,大多数时候不需要遍历,可以通过调用selectNodes、selectSingleNode指定XPath直接读取某个节点或属性:
CComPtr<IXMLDOMDocument>spDoc//DOM
spDoc.CoCreateInstance(CLSID_DOMDocument)
VARIANT_BOOL vb
spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb)//加载XML文件
CComPtr<IXMLDOMElement>spRootEle
spDoc->get_documentElement(&spRootEle)//根节点
CComPtr<IXMLDOMNodeList>spNodeList
CComPtr<IXMLDOMNode>spNode
spRootEle->selectNodes(OLESTR("/root/node2/*"), &spNodeList)//得到node2下的所有子节点
spRootEle->selectSingleNode(OLESTR("/root/node2/childnode1/@attrib1"), &spNode)//得到childnode1的attrib1属性
XPath的语法可以参考XML文档或MSDN。
SDK
SDK中也可以使用智能指针,和MFC没太大区别,同样很方便,直接给代码:
#include <iostream>
#include <tchar.h>
#import <msxml3.dll>
//节点处理函数
void ProcessNode(MSXML2::IXMLDOMNodePtr spNode)
{
std::cout <<"nodeName: " <<spNode->nodeName
if (spNode->nodeType == NODE_ATTRIBUTE || spNode->nodeType == NODE_TEXT)
std::cout <<"\tnodeValue: " <<_bstr_t(spNode->nodeValue)
std::cout <<std::endl
if (spNode->nodeType == NODE_ELEMENT)
{
MSXML2::IXMLDOMNamedNodeMapPtr spNameNodeMap = spNode->attributes
for (long i = 0i != spNameNodeMap->length++i) //遍历节点属性
ProcessNode(spNameNodeMap->item)
MSXML2::IXMLDOMNodeListPtr spNodeList = spNode->childNodes
for (long i = 0i != spNodeList->length++i) //遍历子节点
ProcessNode(spNodeList->item)
}
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL)
//读取XML
MSXML2::IXMLDOMDocumentPtr spXMLDoc
spXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))
spXMLDoc->load(L"stocks.xml")
MSXML2::IXMLDOMElementPtr spRoot = spXMLDoc->documentElement//根节点
MSXML2::IXMLDOMNodeListPtr spNodeList = spRoot->childNodes
for (long i = 0i != spNodeList->length++i) //遍历子节点
ProcessNode(spNodeList->item)
//写入XML
spRoot->selectSingleNode(L"/root/node1")->text = L"newText"
spRoot->selectSingleNode(L"/root/node2/childnode1/@attrib1")->nodeValue = L"newValue"
MSXML2::IXMLDOMNodePtr spNewNode = spRoot->selectSingleNode(L"/root/node2")->appendChild(
spXMLDoc->createNode(_variant_t(NODE_ELEMENT), L"childnode3", L"")
)//给node2创建新子节点childnode3
spNewNode->text = L"childtext2"
MSXML2::IXMLDOMElementPtr spEle = spNewNode
spEle->setAttribute(L"attrib1", _variant_t(L"value1"))//添加新属性
spXMLDoc->save(_variant_t(L"stocks.xml"))
spNewNode.Release()
spEle.Release()
spNodeList.Release()
spRoot.Release()
spXMLDoc.Release()
CoUninitialize()
system("pause")
return 0
}
写MSXML2::IXMLDOMDocumentPtr pDoc
MSXML2::IXMLDOMElementPtr xmlRoot
HRESULT hr=pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))
if (FAILED(hr))
{
AfxMessageBox("无法创建对象,是否安装了MS XML运行库")
return
}
pDoc->raw_createElement((_bstr_t)(char*)"china",&xmlRoot)
pDoc->raw_appendChild(xmlRoot,NULL)
MSXML2::IXMLDOMElementPtr childNode
pDoc->raw_createElement((_bstr_t)(char*)"City",&childNode)
childNode->put_text((_bstr_t)(char*)"WuHan")
childNode->setAttribute((_bstr_t)(char*)"population",CComVariant("8,000,000"))
childNode->setAttribute((_bstr_t)(char*)"area",CComVariant("10000"))
xmlRoot->appendChild(childNode)
pDoc->raw_createElement((_bstr_t)(char*)"City",&childNode)
childNode->put_text((_bstr_t)(char*)"ShangHai")
childNode->setAttribute((_bstr_t)(char*)"population",CComVariant("12,000,000"))
childNode->setAttribute((_bstr_t)(char*)"area",CComVariant("12000"))
xmlRoot->appendChild(childNode)
pDoc->save("e:\\he.xml")
读
MSXML2::IXMLDOMDocumentPtr pDoc
HRESULT hr=pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))
if (FAILED(hr))
{
AfxMessageBox("无法创建对象,是否安装了MS XML运行库")
return
}
pDoc->load("e:\\he.xml")
MSXML2::IXMLDOMElementPtr childNode
childNode=(MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode("//City"))
MSXML2::DOMNodeType nodeType
childNode->get_nodeType(&nodeType)
BSTR var
childNode->get_nodeName(&var)
CString name=(char*)(_bstr_t)var
VARIANT varVal
childNode->get_nodeTypedValue(&varVal)
CString strValue=(char*)(_bstr_t)varVal
MSXML2::IXMLDOMNamedNodeMapPtr pAttrs=NULL
MSXML2::IXMLDOMNodePtr pAttrItem
childNode->get_attributes(&pAttrs)
long nCount
pAttrs->get_length(&nCount)
for(int i=0i<nCounti++)
{
pAttrs->get_item(i,&pAttrItem)
CString strAttrName=(char*)(_bstr_t)pAttrItem->nodeName
CString strAttrValue=(char*)(_bstr_t)pAttrItem->nodeTypedValue
AfxMessageBox(strAttrName+strAttrValue)
}
把上面的代码放到两个按钮下就可以了
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)