XML学习笔记(四)--Delphi读写xml

转自 http://maverick.cnblogs.com/archive/2005/01/12/90459.aspx 

 

有时,只需要用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,程序员的最大乐趣就是自己动手了。我们来改造一下这两个函数。
在原有函数的基础上增加了两个参数:

{-------------------------------------------------------------------------------
  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;

Feedback

#2楼    回复  引用    

2005-03-25 00:51 by satoni [未注册用户]
虽然我一直不是特别理解你这样改了函数原型后带来的实际用处(例如,我必须知道颜色是150才来找name,似乎很牵强);不过你这个帖子还是给了我很大帮助,我建议的是如果有多值,应该循环处理,直到nil为止;

#3楼    回复  引用  查看    

2005-04-02 09:19 by Maverick       
@satoni:
说得有道理,是应该用循环,多谢

#4楼    回复  引用    

2005-04-18 15:09 by 梧桐夜雨 [未注册用户]
getnodefromIXMLNodeList这个函数在哪里定义的

#9楼    回复  引用    

2007-06-05 16:49 by 学习 [未注册用户]
这个还是存在一定的问题,eg
<colour name="normal attribute" red="100"green="125"blue="150"/>
<red sex="男" age="15"/>
<red sex="女" age="17"/>
<colour name="good attribute" red="150" green="175" blue="200"/>
<red sex="同性恋" age="不清楚"/>
<red sex="玻璃" age="未知"/>
<colour name="excellent attribute" red="0" green="0" blue="255"/>
如果我现在想取第二个colour下面的red的值,用上面的函数就没有办法取到,只可以取到第一个colour下面的red的属性值!!

你可能感兴趣的:(xml,Date,String,Integer,Delphi)