Browse Source

dom.pp:
* Partial fix for #13605 (fixes the issue as reported, but a fix for nodelists returned by
GetElementsByTagName[NS] is also needed):
- Each node which can have children has an associated instance of TDOMNodeList;
- Other nodes are substituted by special 'null' node, having an empty child list;
- Muiltiple calls to ChildNodes return the same instance of TDOMNodeList;
- Calling Free on result of ChildNodes is optional; if not freed, it will be destroyed with
the owning node.

tests/domunit.pp:
* Changed TFPObjectList to TObjectList, which has been found to destroy its elements in opposite
order (reported as #13715). As NodeLists became owned by Document, old (FIFO) destruction order is
causing their double destruction.

git-svn-id: trunk@13143 -

sergei 16 years ago
parent
commit
54b475a68b
2 changed files with 19 additions and 4 deletions
  1. 17 2
      packages/fcl-xml/src/dom.pp
  2. 2 2
      packages/fcl-xml/tests/domunit.pp

+ 17 - 2
packages/fcl-xml/src/dom.pp

@@ -259,6 +259,7 @@ type
   protected
     FFirstChild, FLastChild: TDOMNode;
     FChildNodeTree: TAVLTree;
+    FChildNodes: TDOMNodeList;
     function GetFirstChild: TDOMNode; override;
     function GetLastChild: TDOMNode; override;
     procedure CloneChildren(ACopy: TDOMNode; ACloneOwner: TDOMDocument);
@@ -409,6 +410,7 @@ type
     FImplementation: TDOMImplementation;
     FNamespaces: TNamespaces;
     FNames: THashTable;
+    FEmptyNode: TDOMElement;
     function GetDocumentElement: TDOMElement;
     function GetDocType: TDOMDocumentType;
     function GetNodeType: Integer; override;
@@ -1073,7 +1075,8 @@ end;
 destructor TDOMNode_WithChildren.Destroy;
 begin
   FreeChildren;
-  FreeAndNil(FChildNodeTree);  
+  FreeAndNil(FChildNodeTree);
+  FChildNodes.Free; // its destructor will zero the field
   inherited Destroy;
 end;
 
@@ -1308,6 +1311,9 @@ end;
 
 destructor TDOMNodeList.Destroy;
 begin
+  if (FNode is TDOMNode_WithChildren) and
+    (TDOMNode_WithChildren(FNode).FChildNodes = Self) then
+    TDOMNode_WithChildren(FNode).FChildNodes := nil;
   FList.Free;
   inherited Destroy;
 end;
@@ -1744,11 +1750,13 @@ begin
   // Namespace #0 should always be an empty string
   FNamespaces[1] := stduri_xml;
   FNamespaces[2] := stduri_xmlns;
+  FEmptyNode := TDOMElement.Create(Self);
 end;
 
 destructor TDOMDocument.Destroy;
 begin
   FreeAndNil(FIDList);   // set to nil before starting destroying children
+  FEmptyNode.Free;
   inherited Destroy;
   FNames.Free;           // free the nametable after inherited has destroyed the children
                          // (because children reference the nametable)
@@ -1938,7 +1946,14 @@ end;
 
 function TDOMDocument.GetChildNodeList(aNode: TDOMNode): TDOMNodeList;
 begin
-  Result := TDOMNodeList.Create(aNode);
+  if not (aNode is TDOMNode_WithChildren) then
+    aNode := FEmptyNode;
+  Result := TDOMNode_WithChildren(aNode).FChildNodes;
+  if Result = nil then
+  begin
+    Result := TDOMNodeList.Create(aNode);
+    TDOMNode_WithChildren(aNode).FChildNodes := Result;
+  end;
 end;
 
 function TDOMDocument.GetElementList(aNode: TDOMNode; const tagName: DOMString): TDOMNodeList;

+ 2 - 2
packages/fcl-xml/tests/domunit.pp

@@ -36,7 +36,7 @@ type
     function GetTestFilesURI: string; virtual;
   protected
     FParser: TDOMParser;
-    FAutoFree: TFPObjectList;
+    FAutoFree: TObjectList;
     procedure SetUp; override;
     procedure TearDown; override;
     procedure GC(obj: TObject);
@@ -97,7 +97,7 @@ procedure TDOMTestBase.SetUp;
 begin
   FParser := TDOMParser.Create;
   FParser.Options.PreserveWhitespace := True;
-  FAutoFree := TFPObjectList.Create(True);
+  FAutoFree := TObjectList.Create(True);
 end;
 
 procedure TDOMTestBase.TearDown;