有时,只需要用XML作一些小的应用,比如只是简单地保存日志或者一些配置,这时我们只需要直接读写XML就好,效率第一。
Delphi盒子有一个直接读写XML文件 (例子和代码),其核心函数为下面两个函数(一读一写):
{------------------------------------------------------------------------------- Fun/Pro: GetXMLNodeValue @Date: 2004.12.11 @Param: xmlFile xml文件 @Param: xmlnodepath 节点 @Param: xmlattrname 节点中的属性名称,如果直接取节点值则可以忽略此参数。 @Param: dep 节点的参数的分隔符,默认为. @Return: 第一个节点的值 -------------------------------------------------------------------------------} function GetXMLNodeValue(strEntityEngineFile:String; xmlNodePath:String; const xmlattrname:String=''; const dep:Char ='.'):String; var xmlDocument :IXMLDocument; node :IXMLNode; xmlnodeList :TStrings; i :Integer; urlcount :Integer; begin //xml节点路径 xmlnodeList:=TStringList.Create; xmlnodeList.Delimiter:=dep; xmlnodeList.DelimitedText:=xmlnodepath; urlcount:=xmlnodeList.Count; //xml对象 xmlDocument :=TXMLDocument.Create(nil); xmlDocument.LoadFromFile(strEntityEngineFile); xmlDocument.Active:=true; try node:= xmlDocument.DocumentElement; if(node.NodeName = xmlnodeList[0]) then begin //扫描节点 for i := 1 to urlcount-1 do begin if(node<>nil) then node := getnodefromIXMLNodeList(node.ChildNodes,xmlnodeList[i]) else Break; end; if(node=nil)then begin result:=''; end else begin //判断是取属性还是取节点内容 if(Trim(xmlattrname)='') then result:=node.Text else result:=node.AttributeNodes.Nodes[xmlattrname].NodeValue; end; end else begin result:=''; end; except result:='error'; end; xmlDocument.Active:=false; end; {------------------------------------------------------------------------------- Fun/Pro: SetXMLNodeValue @Date: 2004.12.11 @Param: xmlFile xml文件 @Param: xmlnodepath 节点 @Param: xmlattrname 节点中的属性名称,如果直接取节点值则可以忽略此参数。 @Param: dep 节点的参数的分隔符,默认为. @Return: 操作成功否 -------------------------------------------------------------------------------} function setXmlNodeValue(strEntityEngineFile:String; xmlNodePath:String; const xmlattrname:String=''; const value:String=''; const dep:Char ='.'):boolean; var xmlDocument :IXMLDocument; node :IXMLNode; xmlnodeList :TStrings; i :Integer; urlcount :Integer; begin //xml节点路径 xmlnodeList:=TStringList.Create; xmlnodeList.Delimiter:=dep; xmlnodeList.DelimitedText:=xmlnodepath; urlcount:=xmlnodeList.Count; //xml对象 xmlDocument :=TXMLDocument.Create(nil); xmlDocument.LoadFromFile(strEntityEngineFile); xmlDocument.Active:=true; try node:= xmlDocument.DocumentElement; if(node.NodeName = xmlnodeList[0]) then begin //扫描节点 for i := 1 to urlcount-1 do begin if(node<>nil) then node := getnodefromIXMLNodeList(node.ChildNodes,xmlnodeList[i]) else Break; end; if(node <> nil)then begin if(Trim(xmlattrname)='') then node.Text:=value else node.AttributeNodes.Nodes[xmlattrname].NodeValue:=value; xmlDocument.SaveToFile(strEntityEngineFile); end; end; result:=true; except result:=false; end; xmlDocument.Active:=false; end; 但是上述两个函数有一个问题:它只能按节点名和属性名查找第一条记录。举例:如果要操作类似下述XML文件,节点和属性名相同的有多个,只是属性的值不一样,上面的读写函数就罢工了。 <colour name="normal attribute" red="100" green="125" blue="150"/> <colour name="good attribute" red="150" green="175" blue="200"/> <colour name="excellent attribute" red="0" green="0" blue="255"/> OK,程序员的最大乐趣就是自己动手了。我们来改造一下这两个函数。 在原有函数的基础上增加了两个参数: function TOperateXml.getnodefromIXMLNodeList(childnodes: IXMLNodeList; nodename: string): IXMLNode; var i: Integer; begin for i := 1 to childnodes.Count do begin if (childnodes.Get(i - 1).NodeName = nodename) then begin result := childnodes[i - 1]; exit; end; end; end; {------------------------------------------------------------------------------- Fun/Pro: GetXMLNodeSpecialValue @Date: 2004.12.11 @Param: xmlFile xml文件 @Param: xmlnodepath 节点 @Param: xmlattrname 节点中的属性名称,如果直接取节点值则可以忽略此参数。 @Param: XMLSpecialName 要查找的节点中属性名 @Param: XMLSpecialValue 要查找的节点中某属性对应的值 @Param: dep 节点的参数的分隔符,默认为. @Return: 某属性的值 -------------------------------------------------------------------------------} function GetXMLNodeSpecialValue(strEntityEngineFile:String; XMLNodePath:String; const XMLAttrName:String=''; const XMLSpecialName:String=''; const XMLSpecialValue:String=''; const dep:Char ='.'):String; var xmlDocument :IXMLDocument; node :IXMLNode; xmlnodeList :TStrings; i :Integer; urlcount :Integer; begin //xml节点路径 xmlnodeList:=TStringList.Create; xmlnodeList.Delimiter:=dep; xmlnodeList.DelimitedText:=xmlnodepath; urlcount:=xmlnodeList.Count; //xml对象 xmlDocument :=TXMLDocument.Create(nil); xmlDocument.LoadFromFile(strEntityEngineFile); xmlDocument.Active:=true; try node:= xmlDocument.DocumentElement; if(node.NodeName = xmlnodeList[0]) then begin //扫描节点 for i := 1 to urlcount-1 do begin if(node<>nil) then begin node := getnodefromIXMLNodeList(node.ChildNodes,xmlnodeList[i]); end else Break; end; if(node=nil)then begin result:=''; end else begin //判断是取属性还是取节点内容 if(Trim(xmlattrname)='') then result:=node.Text else begin result := node.AttributeNodes.Nodes[XMLSpecialName].NodeValue; //这里不想再声明一个临时变量了,就用result来比较,可能有隐患。 while ((result <> XMLSpecialValue)) do begin node := node.NextSibling; while (node.NodeName = '#comment') do begin node:= node.NextSibling; end; result := node.AttributeNodes.Nodes[XMLSpecialName].NodeValue; end; result:=node.AttributeNodes.Nodes[XMLAttrName].NodeValue; end; end; end else begin result:=''; end; except result:='error'; end; xmlDocument.Active:=false; end; 写函数 {------------------------------------------------------------------------------- Fun/Pro: SetXMLNodeSpecialValue @Date: 2004.12.11 @Param: xmlFile xml文件 @Param: xmlnodepath 节点 @Param: xmlattrname 节点中的属性名称,如果直接取节点值则可以忽略此参数。 @Param: XMLSpecialName 要查找的节点中属性名 @Param: XMLSpecialValue 要查找的节点中某属性对应的值 @Param: dep 节点的参数的分隔符,默认为. @Return: 操作成功与否 -------------------------------------------------------------------------------} function SetXMLNodeSpecialValue(strEntityEngineFile:String; xmlNodePath:String; const xmlattrname:String=''; const value:String=''; const XMLSpecialName:String=''; const XMLSpecialValue:String=''; const dep:Char ='.'):boolean; var xmlDocument :IXMLDocument; node :IXMLNode; xmlnodeList :TStrings; i :Integer; urlcount :Integer; CMPValue :String; begin //xml节点路径 xmlnodeList:=TStringList.Create; xmlnodeList.Delimiter:=dep; xmlnodeList.DelimitedText:=xmlnodepath; urlcount:=xmlnodeList.Count; //xml对象 xmlDocument :=TXMLDocument.Create(nil); xmlDocument.LoadFromFile(strEntityEngineFile); xmlDocument.Active:=true; try node:= xmlDocument.DocumentElement; if(node.NodeName = xmlnodeList[0]) then begin //扫描节点 for i := 1 to urlcount-1 do begin if(node<>nil) then node := getnodefromIXMLNodeList(node.ChildNodes,xmlnodeList[i]) else Break; end; if(node <> nil)then begin {if(Trim(xmlattrname)='') then node.Text:=value else node.AttributeNodes.Nodes[xmlattrname].NodeValue:=value; } if (Trim(XMLAttrName)='') then node.Text := value else begin CMPValue := node.AttributeNodes.Nodes[XMLSpecialName].NodeValue; while (CMPValue <> XMLSpecialValue) do begin node := node.NextSibling; while (node.NodeName = '#comment') do begin node:= node.NextSibling; end; CMPValue := node.AttributeNodes.Nodes[XMLSpecialName].NodeValue; end; node.AttributeNodes.Nodes[XMLAttrName].NodeValue:=value; end; xmlDocument.SaveToFile(strEntityEngineFile); end; end; result:=true; except result:=false; end; xmlDocument.Active:=false; end;