특정 "노드 이름", "속성"및 "속성 값"이있는 노드를 찾으려고합니다. 아래의 재귀 함수를 사용합니다.Delphi XML 재귀 함수, 특정 속성 값을 가진 노드 검색
내 XMLDocument의 값이 '1'인 'Format'속성을 가진 'TestNodeName'노드가 있습니다.
함수는 처음에는 잘 작동합니다. 전달 노드를 반환합니다.
두 번째로 호출하면 잘못된 결과가 나타납니다. 값이 0 인 Format 특성을 가진 노드를 반환합니다.
XML 예제입니다. 몇 가지 테스트 후 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.
의
<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>
끝 나는 마지막으로 기능의 잘못된 결과의 원인을 발견했다. 유사한 재귀 함수가있었습니다. 함수의 호출을 제거 할 때 모든 결과는 괜찮습니다. RecursiveFindNode (ANode : IXMLNode; const SearchNodeName : string) : IXMLNode;
코드에서 다음 코드를 호출합니다. foundNode : = RecursiveFindNode (mnode, 'TestNodeName'); RecursiveFindNodeAttr의 첫 번째 통화로 인해 양호한 결과를 제공한다 "cnode를 ="나는 동일한 변수를 사용하기 때문에 RecursiveFindNodeAttr의 두 번째 호출 (ID = 1) 잘못된 결과를 제공한다 :
"foundNode = RecursiveFindNodeAttr를 (..." 난 "var에 foundNode : IXMLNode을 「이동 마지막글로벌 번째 호출 Tform4 선언에서 좋은 결과를 리턴 (ID = 4) I 다른 문제 발견
나 루프 RecursiveFindNodeAttr 사용할 때 결국 포맷을 대체 ="1. "format ="5 "로 설정하면"foundNode "결과가"nil "이 아니므로 루프가 끝나지 않습니다.
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
내가 설명한 모든 정보를 의견이 아닌 주석에 포함하십시오. 질문을 올바르게하는 법을 배우면 자급 자족 할 수있는 길은 멀어 질 것입니다. –