C++如何 *** 作XML配置文件

C++如何 *** 作XML配置文件,第1张

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

<Cases>

  <case>

    <No>001</No>

    <CopyFile src="C:\test.txt" dest="D:\test.txt"></CopyFile>

  </case>

   

  <case>

    做旦<No>002</No>

    <DelFile>C:\test.txt</DelFile>

  </case>

</Cases>

 

我们用C++来读取上述xml,代码如下:

  

void CTestToolsDlg::ReadXml(CString strXmlPath)

{

    MSXML2::IXMLDOMDocumentPtr pDoc

    ::CoInitialize(NULL)

    HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40)) 

 

    if (!SUCCEEDED(hr)) 

    {  

        MessageBox(_T("创建DOMDocument对象失败。\n请检查运行环境"), _T("错误"), MB_ICONERROR) 

        return

    }

    // 读取xml

    pDoc->put_async(VARIANT_FALSE)

    VARIANT_BOOL bhr = pDoc->load((_variant_t)strXmlPath)

 

    if (bhr != VARIANT_TRUE) {

        MessageBox(_T("无法正确读取xml文件"), _T("错误"), MB_ICONERROR)

        return

    }

 

    // 根节点取得

    MSXML2::IXMLDOMElementPtr root = pDoc->documentElement

    // 取得根节点的名字

    _variant_t strRootName = root->nodeName

    _bstr_t wstrRootName(strRootName.bstrVal)

    MSXML2::IXMLDOMNodeListPtr nodeList = root->GetchildNodes()//cases

     

    // 解析cases的子节点

    ReadCases(nodeList)

}

  

void CTestToolsDlg::ReadCases(MSXML2::IXMLDOMNodeListPtr nodeList)

{

    int ilength = nodeList->Getlength()

    for (int nodeCount = 0 nodeCount < ilength nodeCount++) {

        MSXML2::IXMLDOMNodePtr nodePtr = nodeList->nextNode()

        _variant_t strNodeName = nodePtr->GetnodeName()

        _variant_t 旅胡芦strNodeValue = nodePtr->GetnodeValue()

  

        // 读取case节点下的子节点

        ReadCase(nodePtr->GetchildNodes())

    }

}

 

void CTestToolDlg::ReadCase(MSXML2::IXMLDOMNodeListPtr nodeList)

{

    CString strLogInfo

    strLogInfo.Empty()

    CString strNo              // case编号

    CString strSrcFile         // 源文件

    CString strDestFile        // 目标文件

    for (int nodeCount = 0 nodeCount < nodeList->Getlength() nodeCount++)

    {

        MSXML2::IXMLDOMNodePtr nodePtr = nodeList->nextNode()

        _variant_t strCaseNodeName = nodePtr->GetnodeName()

        _variant_t strCaseNodeValue = nodePtr->Gettext()

        BSTR bStrTemp = strCaseNodeName.bstrVal

        CString strTemp = CString(bStrTemp)

        SysFreeString(bStrTemp)

        CString strNodeName = strTemp

        //  节点的值,如何取得?

        if (0 == strNodeName.CompareNoCase(_T("NO")))

        {

            strNo = (BSTR)strCaseNodeValue.pbstrVal

             

            // 取得的值可以打印出来

            printf(strNo)

        }

  拆带

        // 节点有属性值,该怎么处理?

        else if (0 == strNodeName.CompareNoCase(_T("CopyFile")))

        {

            strSrcFile.Empty()

            strDestFile.Empty()

            // 取得节点的属性值

            MSXML2::IXMLDOMNamedNodeMapPtr pDOMAttrList= nodePtr->Getattributes()

            for (int j = 0 j < pDOMAttrList->Getlength() j++)

            {

                MSXML2::IXMLDOMNodePtr pDOMAttr= pDOMAttrList->Getitem(j) 

                // 取得源文件路径

                if (CompareNoCase((char*)pDOMAttr->GetnodeName(), _T("src")))

                {

                    strSrcFile = pDOMAttr->GetnodeTypedValue()

                    // 取得目标文件路径

                } else if (CompareNoCase((char*)pDOMAttr->GetnodeName(), _T("dest")))

                {

                    strDestFile =pDOMAttr->GetnodeTypedValue()

                }

                 

                CopyFile(strSrcFile, strDestFile, FALSE)

            }

            else if (0 == strNodeName.CompareNoCase(_T("DelFile")))

            {

                strDestFile.Empty()

                strDestFile = CString((BSTR)strCaseNodeValue.pbstrVal)

                 

                DeleteFile(strDestFile)

            } 

        }

    }

为了能够让C++认识MSXML2,我们需要引入相应的dll,代码如下#import "msxml4.dll"

据分析,你的dll类库生成后应该是一些dll文件供winform程序调用,但是生老迅腊成的时候并没有把xml文件生成到dll中去,所以你生成安装文件之后这些xml文件应该没有包含在你的安装昌培程序中,所以会出现如你所说的错误信息,解决方案:可以把配置文件放到winform项目程序中的bin/debug/目录下,然后通过代码获取程序初始目录找到该配置文件侍滑即可。

ML在Win32程序方面应该没有在Web方面应用悔枣得多,很多Win32程序也只是用XML来存存配置信息而已,而且没有足够的好处的话还不如用ini。VC++里 *** 作XML有两个库可以用:MSXML和XmlLite。MSXML又细分了两种接口:DOM和SAX2。XP没自带有XmlLite,只自带有2.x、3.x版的MSXML,不支持SAX2(需要MSXML 4.0以上),所以优先使用DOM。

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

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12341385.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存