Я пытаюсь найти узел с конкретными «именем узла», «атрибутом» и «значением атрибута». Я использую рекурсивную функцию ниже.Delphi XML Рекурсивная функция, поиск узла с определенным значением атрибута
В моем XMLDocument есть узел с именем «TestNodeName» с атрибутом «Формат» со значением «1».
Эта функция работает нормально в первый раз: возвращает узел прокрутки.
Когда я его вызываю во второй раз, он дает неверные результаты: возвращает узел с атрибутом Format со значением 0.
Пример XML.
<mnode>
<TestNodeName ID="1" Format="0">
</TestNodeName>
<TestNodeName ID="2" Format="1">
</TestNodeName>
<TestNodeName ID="3" Format="0">
</TestNodeName>
<TestNodeName ID="4" Format="1">
</TestNodeName>
<TestNodeName ID="5" Format="0">
</TestNodeName>
</mnode>
Конец XML
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, XMLIntf, XMLDoc;
type
TForm4 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
//GLOBAL VARIABLES
var
Form4: TForm4;
XML:IXMLDocument;
mnode:IXMLNode;
s:string;
implementation
{$R *.dfm}
function RecursiveFindNode(ANode: IXMLNode; const SearchNodeName: string): IXMLNode;
var
I: Integer;
begin
if CompareText(ANode.NodeName, SearchNodeName) = 0 then
Result := ANode
else if not Assigned(ANode.ChildNodes) then
Result := nil
else begin
for I := 0 to ANode.ChildNodes.Count - 1 do
begin
Result := RecursiveFindNode(ANode.ChildNodes[I], SearchNodeName);
if Assigned(Result) then
Exit;
end;
end;
end;
function RecursiveFindNodeAttr(ANode: IXMLNode; const SearchNodeName: string; sAttr, sAttrVal:string): IXMLNode;
var
I: Integer;
sAttrFind: ixmlnode;
stext:string;
begin
sAttrFind:=ANode.AttributeNodes.FindNode(sAttr);
if sAttrFind<>nil then stext:=sAttrFind.Text else stext:='';
if (CompareText(ANode.NodeName, SearchNodeName)=0)and(CompareText(sAttrFind.NodeName, sAttr)=0)and(CompareText(stext, sAttrVal)=0) then
begin
Result := ANode;
end
else if not Assigned(ANode.ChildNodes) then
begin
Result := nil;
end
else begin
for I := 0 to ANode.ChildNodes.Count - 1 do
begin
Result := RecursiveFindNodeAttr(ANode.ChildNodes[I], SearchNodeName, sAttr, sAttrVal);
if Assigned(Result) then
begin
Exit;
end;
end;
end;
end;
procedure TForm4.FormCreate(Sender: TObject);
var
cnode,foundNode:IXMLNode; //<-- Problem here "foundNode" must be in global
begin
XML:= NewXMLDocument;
XML.LoadFromFile('C:\test.xml');
mnode:=XML.DocumentElement;
foundNode:=RecursiveFindNode(mnode,'TestNodeName');
//First time
cnode:=RecursiveFindNodeAttr(XML.DocumentElement,'TestNodeName','Format','1');
if cnode<>nil then
begin
cnode.Attributes['Format']:='5';
ShowMessage('ID='+cnode.Attributes['ID']);
end
else
ShowMessage('nil');
//Second time
foundNode:=RecursiveFindNodeAttr(XML.DocumentElement,'TestNodeName','Format','1');
if foundNode<>nil then
begin
foundNode.Attributes['Format']:='5';
ShowMessage('ID='+foundNode.Attributes['ID']);
end
else
ShowMessage('nil');
XML.SaveToFile('C:\test.xml');
end;
end.
После нескольких испытаний я наконец нашел то, что вызвало неверный результат функции. Была аналогичная рекурсивная функция. Когда я удалил вызов функции, все результаты были в порядке. RecursiveFindNode (ANode: IXMLNode; const SearchNodeName: string): IXMLNode;
В нижеследующем коде находится foundNode: = RecursiveFindNode (mnode, 'TestNodeName'); Первый вызов RecursiveFindNodeAttr даст хороший результат из-за «cnode: =» Второй вызов RecursiveFindNodeAttr даст неправильный результат (ID = 1), так как я использовал ту же переменную «foundNode: = RecursiveFindNodeAttr (...»
Наконец, когда я переместил «var foundNode: IXMLNode;» из объявления Tform4 в глобальный, второй вызов возвратил хороший результат (ID = 4)
Я нашел еще одну проблему. Когда я использую цикл RecursiveFindNodeAttr взамен, замените все format = "1 «to format =« 5 », результат« foundNode »остается« не ноль », поэтому цикл никогда не будет завершен.
foundNode:=RecursiveFindNodeAttr(XML.DocumentElement,'TestNodeName','Format','1');
while foundNode<>nil do
begin
foundNode.Attributes['Format']:='5';
ShowMessage('ID='+foundNode.Attributes['ID']);
foundNode:=RecursiveFindNodeAttr(XML.DocumentElement,'TestNodeName','Format','1');
if foundNode=nil then ShowMessage('nil');
end;
"Это дает неправильные результаты" нет смысла нам. Вам необходимо предоставить входной XML, параметры, которые вы передаете функции, ожидаемый результат и фактический результат. Помните, что мы не видим ваш экран. Пожалуйста, отредактируйте вопрос, чтобы указать недостающую деталь. –
Это дает неправильные результаты, когда я называю это второй раз в программе.Он возвращает значение атрибута узла даже не «1» (проверьте пример вызова выше), но он должен вернуть «nil». – Nafalem
Пожалуйста, включите в вопрос, а не комментарии, всю информацию, которую я описал. Изучение того, как правильно задавать вопрос, проделает долгий путь к самообеспечению. –