转自 http://maverick.cnblogs.com/archive/2005/01/12/90459.aspx
有时,只需要用XML作一些小的应用,比如只是简单地保存日志或者一些配置,这时我们只需要直接读写XML就好,效率第一。
Delphi盒子有一个 直接读写XML文件 (例子和代码),其核心函数为下面两个函数(一读一写):
但是上述两个函数有一个问题:它只能按节点名和属性名查找第一条记录。举例:如果要操作类似下述XML文件,节点和属性名相同的有多个,只是属性的值不一样,上面的读写函数就罢工了。
OK,程序员的最大乐趣就是自己动手了。我们来改造一下这两个函数。
在原有函数的基础上增加了两个参数:
写函数
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;
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" />
< colour name ="good attribute" red ="150" green ="175" blue ="200" />
< colour name ="excellent attribute" red ="0" green ="0" blue ="255" />
在原有函数的基础上增加了两个参数:
{-------------------------------------------------------------------------------
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: 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;
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
2005-03-25 00:51 by
satoni [未注册用户]
虽然我一直不是特别理解你这样改了函数原型后带来的实际用处(例如,我必须知道颜色是150才来找name,似乎很牵强);不过你这个帖子还是给了我很大帮助,我建议的是如果有多值,应该循环处理,直到nil为止;
#4楼 回复 引用
2005-04-18 15:09 by 梧桐夜雨 [未注册用户]
getnodefromIXMLNodeList这个函数在哪里定义的
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的属性值!!
<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的属性值!!