Browse Source

* (re)Build element ID list at end of parse. Fixes issue #39391

Michaël Van Canneyt 1 year ago
parent
commit
9588204585
2 changed files with 45 additions and 0 deletions
  1. 39 0
      packages/fcl-xml/src/dom.pp
  2. 6 0
      packages/fcl-xml/src/sax_html.pp

+ 39 - 0
packages/fcl-xml/src/dom.pp

@@ -522,6 +522,8 @@ type
     // Extensions to DOM interface:
     // Extensions to DOM interface:
     constructor Create; virtual;
     constructor Create; virtual;
     destructor Destroy; override;
     destructor Destroy; override;
+    procedure RebuildIDsOfElement(aRoot: TDOMElement);
+    procedure RebuildIDList;
     function CloneNode(deep: Boolean): TDOMNode; overload; override;
     function CloneNode(deep: Boolean): TDOMNode; overload; override;
     property Names: THashTable read FNames;
     property Names: THashTable read FNames;
     property IDs: THashTable read FIDList write FIDList;
     property IDs: THashTable read FIDList write FIDList;
@@ -2261,6 +2263,43 @@ begin
                          // (because children reference the nametable)
                          // (because children reference the nametable)
 end;
 end;
 
 
+procedure TDOMDocument.RebuildIDsOfElement(aRoot: TDOMElement);
+var
+  i: Integer;
+  AttribNode: TDOMNode;
+  id: DOMString;
+  Item: PHashItem;
+begin
+  if aRoot=Nil then 
+    exit;
+  for i := 0 to aRoot.Attributes.Length - 1 do
+  begin
+    AttribNode := aRoot.Attributes.Item[i];
+    if LowerCase(AttribNode.NodeName) = 'id' then
+    begin
+      id := AttribNode.TextContent;
+      Item := FIDList.FindOrAdd(PWideChar(id), Length(id));
+      Item^.Data := aRoot;
+      break;
+    end;
+  end;
+
+  for i := 0 to aRoot.ChildNodes.Count - 1 do
+  begin
+    if aroot.ChildNodes[i] is TDOMElement then
+      RebuildIDsOfElement(TDOMElement(aroot.ChildNodes[i]));
+  end;
+end;
+
+procedure TDOMDocument.RebuildIDList;
+begin
+  if not Assigned(FIDList) then
+    FIDList := THashTable.Create(256, False);
+  FIDList.Clear;
+  RebuildIDsOfElement(Self.DocumentElement);
+end;    
+
+
 function TDOMDocument.CloneNode(deep: Boolean): TDOMNode;
 function TDOMDocument.CloneNode(deep: Boolean): TDOMNode;
 type
 type
   TDOMDocumentClass = class of TDOMDocument;
   TDOMDocumentClass = class of TDOMDocument;

+ 6 - 0
packages/fcl-xml/src/sax_html.pp

@@ -114,6 +114,7 @@ type
     constructor Create(AReader: THTMLReader; ADocument: TDOMDocument);
     constructor Create(AReader: THTMLReader; ADocument: TDOMDocument);
     constructor CreateFragment(AReader: THTMLReader; AFragmentRoot: TDOMNode);
     constructor CreateFragment(AReader: THTMLReader; AFragmentRoot: TDOMNode);
     destructor Destroy; override;
     destructor Destroy; override;
+    Property Document : TDOMDocument Read FDocument;
   end;
   end;
 
 
 
 
@@ -781,6 +782,7 @@ begin
     Converter := THTMLToDOMConverter.Create(Reader, ADoc);
     Converter := THTMLToDOMConverter.Create(Reader, ADoc);
     try
     try
       Reader.ParseStream(f);
       Reader.ParseStream(f);
+      Converter.Document.RebuildIDList;
     finally
     finally
       Converter.Free;
       Converter.Free;
     end;
     end;
@@ -811,6 +813,10 @@ begin
     Converter := THTMLToDOMConverter.CreateFragment(Reader, AParentNode);
     Converter := THTMLToDOMConverter.CreateFragment(Reader, AParentNode);
     try
     try
       Reader.ParseStream(f);
       Reader.ParseStream(f);
+      if aParentNode is TDOMElement then
+        Converter.Document.RebuildIDsOfElement(aParentNode as TDOMElement)
+      else
+        Converter.Document.RebuildIDList;
     finally
     finally
       Converter.Free;
       Converter.Free;
     end;
     end;