Browse Source

* xmlread.pp, continued reducing DOM dependencies:
* TContentParticle only stores and compares a pointer to an element definition, a particular type of that definition doesn't matter - so change it to TObject.
* In case of mixed content model, assign Type and Quantity to the root content particle, and process it the same way as element-only models.
* While parsing, store entities in THashTable instead of TDOMNamedNodeMap.
* Assign Prefix to element and attribute NodeData.

git-svn-id: trunk@16208 -

sergei 15 years ago
parent
commit
b585a6a1d0
1 changed files with 49 additions and 30 deletions
  1. 49 30
      packages/fcl-xml/src/xmlread.pp

+ 49 - 30
packages/fcl-xml/src/xmlread.pp

@@ -284,12 +284,12 @@ type
   public
   public
     CPType: TCPType;
     CPType: TCPType;
     CPQuant: TCPQuant;
     CPQuant: TCPQuant;
-    Def: TDOMElementDef;
+    Def: TObject;
     destructor Destroy; override;
     destructor Destroy; override;
     function Add: TContentParticle;
     function Add: TContentParticle;
     function IsRequired: Boolean;
     function IsRequired: Boolean;
-    function FindFirst(aDef: TDOMElementDef): TContentParticle;
-    function FindNext(aDef: TDOMElementDef; ChildIdx: Integer): TContentParticle;
+    function FindFirst(aDef: TObject): TContentParticle;
+    function FindNext(aDef: TObject; ChildIdx: Integer): TContentParticle;
     function MoreRequired(ChildIdx: Integer): Boolean;
     function MoreRequired(ChildIdx: Integer): Boolean;
     property ChildCount: Integer read GetChildCount;
     property ChildCount: Integer read GetChildCount;
     property Children[Index: Integer]: TContentParticle read GetChild;
     property Children[Index: Integer]: TContentParticle read GetChild;
@@ -300,6 +300,8 @@ type
     // generic members
     // generic members
     FNext: PNodeData;
     FNext: PNodeData;
     FQName: PHashItem;
     FQName: PHashItem;
+    FPrefix: PHashItem;
+    FNsUri: PHashItem;
     FNodeType: TXMLNodeType;
     FNodeType: TXMLNodeType;
     FDOMNode: TDOMNode_WithChildren;   // temporary
     FDOMNode: TDOMNode_WithChildren;   // temporary
 
 
@@ -355,7 +357,8 @@ type
     FStandalone: Boolean;          // property of Doc ?
     FStandalone: Boolean;          // property of Doc ?
     FNamePages: PByteArray;
     FNamePages: PByteArray;
     FDocType: TDOMDocumentTypeEx;  // a shortcut
     FDocType: TDOMDocumentTypeEx;  // a shortcut
-    FPEMap: TDOMNamedNodeMap;
+    FPEMap: THashTable;
+    FGEMap: THashTable;
     FIDRefs: TFPList;
     FIDRefs: TFPList;
     FNotationRefs: TFPList;
     FNotationRefs: TFPList;
     FCurrContentType: TElementContentType;
     FCurrContentType: TElementContentType;
@@ -1347,6 +1350,7 @@ begin
     while ContextPop(True) do;     // clean input stack
     while ContextPop(True) do;     // clean input stack
   FSource.Free;
   FSource.Free;
   FPEMap.Free;
   FPEMap.Free;
+  FGEMap.Free;
   ClearRefs(FNotationRefs);
   ClearRefs(FNotationRefs);
   ClearRefs(FIDRefs);
   ClearRefs(FIDRefs);
   FNsAttHash.Free;
   FNsAttHash.Free;
@@ -1799,12 +1803,12 @@ var
   PEName: WideString;
   PEName: WideString;
   PEnt: TDOMEntityEx;
   PEnt: TDOMEntityEx;
 begin
 begin
-  SetString(PEName, FName.Buffer, FName.Length);
   PEnt := nil;
   PEnt := nil;
   if Assigned(FPEMap) then
   if Assigned(FPEMap) then
-    PEnt := FPEMap.GetNamedItem(PEName) as TDOMEntityEx;
+    PEnt := FPEMap.Get(FName.Buffer, FName.Length) as TDOMEntityEx;
   if PEnt = nil then
   if PEnt = nil then
   begin
   begin
+    SetString(PEName, FName.Buffer, FName.Length);
     ValidationError('Undefined parameter entity ''%s'' referenced', [PEName], FName.Length+2);
     ValidationError('Undefined parameter entity ''%s'' referenced', [PEName], FName.Length+2);
     // cease processing declarations, unless document is standalone.
     // cease processing declarations, unless document is standalone.
     FDTDProcessed := FStandalone;
     FDTDProcessed := FStandalone;
@@ -2315,6 +2319,8 @@ begin
         FSource.NextChar;
         FSource.NextChar;
         if (not CheckForChar('*')) and (CP.ChildCount > 0) then
         if (not CheckForChar('*')) and (CP.ChildCount > 0) then
           FatalError(WideChar('*'));
           FatalError(WideChar('*'));
+        CP.CPQuant := cqZeroOrMore;
+        CP.CPType := ctChoice;
       end
       end
       else       // Children section [47]
       else       // Children section [47]
       begin
       begin
@@ -2510,21 +2516,26 @@ end;
 
 
 procedure TXMLReader.ParseEntityDecl;        // [70]
 procedure TXMLReader.ParseEntityDecl;        // [70]
 var
 var
-  IsPE: Boolean;
+  IsPE, Exists: Boolean;
   Entity: TDOMEntityEx;
   Entity: TDOMEntityEx;
-  Map: TDOMNamedNodeMap;
+  Map: THashTable;
+  Item: PHashItem;
 begin
 begin
   if not SkipWhitespace(True) then
   if not SkipWhitespace(True) then
     FatalError('Expected whitespace');
     FatalError('Expected whitespace');
-  IsPE := False;
-  Map := FDocType.Entities;
-  if CheckForChar('%') then                  // [72]
+  IsPE := CheckForChar('%');
+  if IsPE then                  // [72]
   begin
   begin
     ExpectWhitespace;
     ExpectWhitespace;
-    IsPE := True;
     if FPEMap = nil then
     if FPEMap = nil then
-      FPEMap := TDOMNamedNodeMap.Create(FDocType, ENTITY_NODE);
+      FPEMap := THashTable.Create(64, True);
     Map := FPEMap;
     Map := FPEMap;
+  end
+  else
+  begin
+    if FGEMap = nil then
+      FGEMap := THashTable.Create(64, False);
+    Map := FGEMap;
   end;
   end;
 
 
   Entity := TDOMEntityEx.Create(Doc);
   Entity := TDOMEntityEx.Create(Doc);
@@ -2534,6 +2545,7 @@ begin
     Entity.FIsPE := IsPE;
     Entity.FIsPE := IsPE;
     Entity.FName := ExpectName;
     Entity.FName := ExpectName;
     CheckNCName;
     CheckNCName;
+    Item := Map.FindOrAdd(FName.Buffer, FName.Length, Exists);
     ExpectWhitespace;
     ExpectWhitespace;
 
 
     // remember where the entity is declared
     // remember where the entity is declared
@@ -2573,8 +2585,12 @@ begin
   end;
   end;
 
 
   // Repeated declarations of same entity are legal but must be ignored
   // Repeated declarations of same entity are legal but must be ignored
-  if FDTDProcessed and (Map.GetNamedItem(Entity.FName) = nil) then
-    Map.SetNamedItem(Entity)
+  if FDTDProcessed and not Exists then
+  begin
+    Item^.Data := Entity;
+    if not IsPE then
+      FDocType.Entities.SetNamedItem(Entity);
+  end
   else
   else
     Entity.Free;
     Entity.Free;
 end;
 end;
@@ -3038,6 +3054,12 @@ begin
   PushVC(NewElem, ElDef);  // this increases FNesting
   PushVC(NewElem, ElDef);  // this increases FNesting
   FCurrNode^.FQName := ElName;
   FCurrNode^.FQName := ElName;
   FCurrNode^.FNodeType := ntElement;
   FCurrNode^.FNodeType := ntElement;
+  if FNamespaces then
+  begin
+    FNSHelper.StartElement;
+    if FColonPos > 0 then
+      FCurrNode^.FPrefix := FNSHelper.GetPrefix(FName.Buffer, FColonPos-1);
+  end;
 
 
   while (FSource.FBuf^ <> '>') and (FSource.FBuf^ <> '/') do
   while (FSource.FBuf^ <> '>') and (FSource.FBuf^ <> '/') do
   begin
   begin
@@ -3254,8 +3276,6 @@ var
   PrefixCount: Integer;
   PrefixCount: Integer;
   b: TBinding;
   b: TBinding;
 begin
 begin
-  FNSHelper.StartElement;
-
   PrefixCount := 0;
   PrefixCount := 0;
   if Element.HasAttributes then
   if Element.HasAttributes then
   begin
   begin
@@ -3410,7 +3430,10 @@ begin
         EndPos := StartPos;
         EndPos := StartPos;
         while (EndPos <= L) and (aValue[EndPos] <> #32) do
         while (EndPos <= L) and (aValue[EndPos] <> #32) do
           Inc(EndPos);
           Inc(EndPos);
-        Entity := TDOMEntity(FDocType.Entities.GetNamedItem(Copy(aValue, StartPos, EndPos-StartPos)));
+        if Assigned(FGEMap) then
+          Entity := TDOMEntity(FGEMap.Get(@aValue[StartPos], EndPos-StartPos))
+        else
+          Entity := nil;
         if (Entity = nil) or (Entity.NotationName = '') then
         if (Entity = nil) or (Entity.NotationName = '') then
           ValidationError('Attribute ''%s'' type mismatch', [Attr.Name], -1);
           ValidationError('Attribute ''%s'' type mismatch', [Attr.Name], -1);
         StartPos := EndPos + 1;
         StartPos := EndPos + 1;
@@ -3522,6 +3545,8 @@ begin
   Result := AllocNodeData(FNesting + FAttrCount + 1);
   Result := AllocNodeData(FNesting + FAttrCount + 1);
   Result^.FNodeType := ntAttribute;
   Result^.FNodeType := ntAttribute;
   Result^.FQName := AName;
   Result^.FQName := AName;
+  Result^.FPrefix := nil;
+  Result^.FNsUri := nil;
   Inc(FAttrCount);
   Inc(FAttrCount);
 end;
 end;
 
 
@@ -3589,6 +3614,7 @@ begin
   FCurrNode^.FElementDef := aElDef;
   FCurrNode^.FElementDef := aElDef;
   FCurrNode^.FCurCP := nil;
   FCurrNode^.FCurCP := nil;
   FCurrNode^.FFailed := False;
   FCurrNode^.FFailed := False;
+  FCurrNode^.FPrefix := nil;
   UpdateConstraints;
   UpdateConstraints;
 end;
 end;
 
 
@@ -3617,7 +3643,6 @@ end;
 
 
 function TNodeData.IsElementAllowed(Def: TDOMElementDef): Boolean;
 function TNodeData.IsElementAllowed(Def: TDOMElementDef): Boolean;
 var
 var
-  I: Integer;
   Next: TContentParticle;
   Next: TContentParticle;
 begin
 begin
   Result := True;
   Result := True;
@@ -3625,18 +3650,12 @@ begin
   if Assigned(Def) and Assigned(FElementDef) then
   if Assigned(Def) and Assigned(FElementDef) then
   begin
   begin
     case FElementDef.ContentType of
     case FElementDef.ContentType of
-      ctMixed: begin
-        for I := 0 to FElementDef.RootCP.ChildCount-1 do
-        begin
-          if Def = FElementDef.RootCP.Children[I].Def then
-          Exit;
-        end;
-        Result := False;
-      end;
 
 
       ctEmpty: Result := False;
       ctEmpty: Result := False;
 
 
-      ctChildren: begin
+      ctChildren, ctMixed: begin
+        if FFailed then     // if already detected a mismatch, don't waste time
+          Exit;
         if FCurCP = nil then
         if FCurCP = nil then
           Next := FElementDef.RootCP.FindFirst(Def)
           Next := FElementDef.RootCP.FindFirst(Def)
         else
         else
@@ -3733,7 +3752,7 @@ begin
     Result := FParent.MoreRequired(FIndex);
     Result := FParent.MoreRequired(FIndex);
 end;
 end;
 
 
-function TContentParticle.FindFirst(aDef: TDOMElementDef): TContentParticle;
+function TContentParticle.FindFirst(aDef: TObject): TContentParticle;
 var
 var
   I: Integer;
   I: Integer;
 begin
 begin
@@ -3759,7 +3778,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-function TContentParticle.FindNext(aDef: TDOMElementDef;
+function TContentParticle.FindNext(aDef: TObject;
   ChildIdx: Integer): TContentParticle;
   ChildIdx: Integer): TContentParticle;
 var
 var
   I: Integer;
   I: Integer;