文章探索:   分类:    关键字:  
  + 栏目导航
  + 相关文章
Ajax核心:XMLHTTP组件相关技术资料
远程获取内容,并将内容存在本地电脑..
xmlhttp组件获取远程文件并筛选出目标..
XMLHTTP对象及其方法
把HTML表单提交的数据转化成XML文件
利用XMLHTTP无刷新添加数据之Post篇
Js+Xml:不刷新页面获取对应网址的网页..
xml(元标记语言)学习基础一
Java语言编程中更新XML文档的常用方法..
简析JAVA中的XML编程
XML及其技术指南
XML教程(2)--XML元素与XML属性值
XML教程(1)--严格的语法
从XML到Java代码的数据绑定之一
神奇的XML--突破CGI权限的约束
基于XML的数据库总体分析
XML 中的常见问题(3)
XML 中的常见问题(2)
XML 中的常见问题(1)
一个简单的XML Schema的例子
Web设计中如何使用XML数据3
Web设计中如何使用XML数据2
Web设计中如何使用XML数据1
大话XML(3)XML的语法
构造未来Web页面的工具语言-- XML
不离开页面刷新数据
文件上传的实现
XML的产生
将XML文件链接至HTML网页
动态产生XML文档的几种方式


技术教程 -> XML教程 ->  
XML文件处理的思考
来源:转载   人气:830   录入时间:2007-11-8
    
   1。用分隔符隔开的字符串表示节点路径信息(BCB)。思考原因,一些简单的参数,如果嵌
   套的比较深入的话,如果用一般XML处理的方法,逐步深入,需要定义好些变量,太麻烦。
   
   
   假设XML文件为
   <XNETCONFIG>
   <LOCALNAME>ohahu</LOCALNAME>
   <PORT>6800</PORT>
   <MAXCLIENT>50</MAXCLIENT>
   </XNETCONFIG>
   
   访问XNetConfig的Port子节点的方法需要先获取XNetConfig节点,然后再获取Port节点。
   下面通过通过字符串“XNetConfig.Port”来直接获取Port节点。
   函数实现如下:
   //定义一个回调函数模板。这样,对于所有找节点的操作就不用关心,只要关心你要对这
   个节点做什么
   //函数 返回值类型bool *表示是指针 ActionProc名称 参数_di_IXMLNode pNode,void *
   pValue(void *pValue为自适应)
   typedef bool (*ActionProc)(_di_IXMLNode pNode,void *pValue);
   
   //AnsiString和CString是类似的
   bool RetrieveNodeByDir(_di_IXMLNode pParent,AnsiString strList,void *pValue,Ac
   tionProc doit)
   {
   try
   {
   _di_IXMLNodeList ChildList = pParent->ChildNodes;
   if(ChildList==NULL||strList==NULL)
   return false;//节点不存在,自然处理就不成功了
   else
   {
   _di_IXMLNode ChildNode;
   int nLen = strList.AnsiPos(".")>0?strList.AnsiPos(".")-1:strList.L
   ength();
   AnsiString strCur = strList.SubString(1,nLen);//这个地方测试不够充
   分
   if((ChildNode = ChildList->FindNode(WideString(strCur)))!=NULL)
   {
   if(strCur==strList)
   {
   return doit(ChildNode,pValue);//调用处理函数
   }
   else
   {
   int nStart = strList.AnsiPos(".")>0?strList.AnsiPos(".")+1
   :1;
   strCur = strList.SubString(nStart,strList.Length());
   if(GetXMLMinNodeByDir(ChildNode,strCur,pValue,doit))//递归
   调用,处理子节点
   return true;
   }
   }
   }
   }
   catch(...)
   {
   return false;
   }
   return false;
   }
   这个函数,可以通过ActionProc来执行设置节点值、属性,获取节点值、属性,等操作。
   后面有ActionProc的范例
   
   ////----------------------------------------------------------------------------------------------
   2。根据节点名称来查找节点
   
   如上面的Port节点,只需要一个”Port”作为参数,而不需要完整路径。当然,这样如果
   整个文档有多个Port的时候,将不能识别,但是可以经过修改,使这个函数能支持查找所
   有符合条件的节点。如果能和上面一样加入回调函数更好。
   函数如下:
   bool GetTextIntByTag(_di_IXMLNode pParent,AnsiString strTag,int &nValue)
   {
   //bool bSuccess = false;
   _di_IXMLNodeList ChildList = pParent->ChildNodes;
   if(ChildList==NULL||strTag==NULL)
   return false;
   else
   {
   _di_IXMLNode ChildNode;
   if((ChildNode = ChildList->FindNode(WideString(strTag)))!=0&&
   ChildNode->ChildNodes!=NULL&&ChildNode->ChildNodes->Count==1)
   {
   int nOldValue = nValue;
   try
   {
   AnsiString str;
   str = ChildNode->Text;
   nValue = str.ToInt();
   return true;
   }
   catch(...)
   {
   nValue = nOldValue;
   }
   }
   else
   {
   for(int i=0;iCount;i++)
   {
   ChildNode = ChildList->GetNode(i);
   if(GetXMLTextIntByTag(ChildNode,strTag,nValue))
   return true;
   }
   }
   }
   return false;
   }
   
   ////----------------------------------------------------------------------------------------------
   3。从上面可以看出,在遍历的函数中使用回调函数是一个非常好的选择。当然要定义一个
   良好的回调函数,这个就是C++的优势,比如在上面的void指针,我们可以把void指针随便
   转换成需要的类型。指针的转换,除了下面的直接转换以外,还有dynamic_cast,static
   _cast,const_cast,其中static_cast用的比较多,具体的还是自己找资料去。做程序,少
   不了的就是找资料。
   
   第一个函数的回调函数示例:
   //获取节点属性
   bool GetNodeStr(_di_IXMLNode pNode,void *pValue)
   {
   AnsiString strOldValue = *(AnsiString *)pValue;//转换成字符串指针,然后取得
   这个对象
   try
   {//把节点的信息放到pValue中,下面这样赋值个人觉得是没有什么问题,因为在外面
   定义的是AnsiString,然后这里按照AnsiString的规则来处理它,当然如果外面定义pValu
   e是一个指向int的指针,我就不知道会发生什么事了
   *(AnsiString*)pValue = pNode->Text;
   return true;
   }
   catch(...)
   {
   *(AnsiString*)pValue = strOldValue;
   }
   return false;
   }
   
   //设置节点属性
   bool SetNodeStr(_di_IXMLNode pNode,void *pValue)
   {
   try
   {
   //设置节点的值,这里的_di_IXMLNode是COM接口,所以这里要用WideString
   pNode->Text = WideString(*(AnsiString*)pValue);
   return true;
   }
   catch(...)
   {
   return false;
   }
   }
   
   使用示例:
   //DocNode是指向XML文档节点的接口(指针??),对于上面来说就是XNetConfig节点
   int nValue = Left;
   RetrieveNodeByDir(DocNode,AnsiString("MainForm.Left"),(void*)&nValue,SetNodeI
   nt);
   if(RetrieveNodeByDir(DocNode,AnsiString("MainForm.Left"),(void*)&nValue,GetNod
   eInt))
   Left = nValue;
   用AnsiString的例子
   AnsiString strValue = Caption;
   RetrieveNodeByDir(DocNode,AnsiString("MainForm.Caption"),(void*)&strValue,Set
   NodeStr);
   if(RetrieveNodeByDir(DocNode,AnsiString("MainForm.Caption"),(void*)&strValue,G
   etNodeStr))
   Caption = strValue;
   也许有人不明白用回调函数的意义是什么,顺便啰嗦两句。
   一个比较浅显的应用是把上面1(包括typedef),其实可以把它封装到dll文件中(这里不考虑线程问题),这样在Exe中动态调用(LoadLibrary,GetProcAddress)的时候,只要指定一个实现的函数,比如上面的设值,读值等,就可以使用了,完全不用关心,如何去按照“xxx.aa”这样的路径怎么找到等实现细节。而且,对于实现不同的功能,这样检索路径的代码,只需要写一次就行了。需要注意的是,ActionProc必须是一个固定的结构(参数,返回值),可能是不同的数据类型,但占的字节数,必须一样。
   
   ////----------------------------------------------------------------------------------------------
   4.上面提到_di_IXMLNode是一个接口,Com的调用多有一个差不多的规律,当然,在VC中有不同的实现过程,这里说一下我觉得有必要说的XML的Com调用的部分内容
   #import "C:\\Windows\\system32\\MSXML.DLL" named_guids
   在stdafx.h里面加入这句,引入XML调用,相关可以看
   //初识Com的应用总结
   //http://bbs.hziee.edu.cn/bbscon.php?board=vc&id=239
   
   在微软的许多COM中常常出现的get__newEnum的使用,懂得了他的使用方法,也就知道了怎么遍历
   具体也不说很多了,先把遍历节点的代码贴出来,因为,自己对COM的机理也没有很大的把握,下面说错了,可不要扔石头啊,呵呵
   //还是一个回调函数
   typedef void (*EnumNodeProc)(MSXML::IXMLDOMNodePtr pElement);
   
   INT CXmlFile::EnumNode(MSXML::IXMLDOMNodeListPtr pNodeList, EnumNodeProc EnumProc)
   {
   if(pNodeList==NULL)
   return 0;
   MSXML::IXMLDOMNodePtr pNode;
   CComPtr spDispatch;
   IUnknownPtr pUnk;
   int nCnt = 0;
   try
   {
   HRESULT hr = pNodeList->get__newEnum(&pUnk);//这里生成了pUnk对COM的接口调用
   if(FAILED(hr))
   {
   return nCnt;
   }
   CComPtr pEnum;
   //但是pUnk还不是Enum接口,但是Enum接口已经包含在pUnk里面了,
   //在这里pUnk是不是IUnknownPtr接口并不重要,重要的是它要包含IEnum接口
   //但是,前面get_newEnum需要是IUnknown接口。
   hr = pUnk->QueryInterface(IID_IEnumVARIANT,(VOID**)&pEnum);//生成IEnum调用
   if(pEnum)
   {
   pEnum->Reset();
   ULONG fget = 1;
   while(SUCCEEDED(hr)&&fget>0)
   {
   _variant_t varDisp;
   hr = pEnum->Next(1,&varDisp,&fget);//下一个记录
   if(SUCCEEDED(hr) && fget>0)
   {
   pNode = varDisp.pdispVal;
   nCnt++;
   EnumProc(pNode);//调用回调函数
   pNode = NULL;
   }
   }
   pEnum.Release();//有调用就需要释放,COM的记数准确,才能在没有调用的时候自动释放
   }
   pUnk.Release();
   }
   catch(_com_error &e)
   {
   ;
   }
   return nCnt;
   }
   上面关于get_newEnum的用法,来自CSDN论坛VC版老大哥masterz的指导,另外还有一个成员_newEnum的使用,我也没有试出来,参考上面的方法,老是出错,如果有哪位试出来了,麻烦告知。
   COM的处理流程在《vc技术内幕 第五版》的电子版第四章(到网上找一下)中有较好的介绍。
   
   ?
   
   6月26日 2:43补:关键字:字符串定位XML节点,XML插入节点
   
   竟然发现MSXML中本身就带了用字符串查找节点的函数,汗
   
   参考: http://www.vcer.net/showTip.jsp?tipid=2248
   
   使用方法如下:
   MSXML::IXMLDOMDocumentPtr m_pDoc;
   MSXML::IXMLDOMNodePtr NodePtr=NULL;
   if((NodePtr=m_pDoc->selectSingleNode(_bstr_t("distributeservice/mainservice")))!=NULL)
   printf("Find distributeservice/mainservice\n");
   
   再有需要添加节点都是由XMLDocument创建出来,再由子节点插入的,如
   
   ?MSXML::IXMLDOMDocumentPtr pDoc;
   MSXML::IXMLDOMElementPtr pElem = NULL;
   pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));
   pDoc->loadXML(_bstr_t("<test>hello</test>"));
   pElem = pDoc->GetdocumentElement();
   if(pElem!=NULL)
   {
   _bstr_t tmp = pElem->Getxml();
   pElement->appendChild((MSXML::IXMLDOMNodePtr)pElem);//发现没有,这样也行
   }
   pDoc.Release();
   pDoc=NULL;
   




Copyright(C)2007-2024 广州市佳沛数码科技有限公司 版权所有
公司地址: 广州市荔湾区东漖北路560号511室
电话:020-81803473 传真:020-81544987