* 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 -
This commit is contained in:
sergei 2010-10-23 18:20:49 +00:00
parent a723c86cb1
commit b585a6a1d0

View File

@ -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 FindFirst(aDef: TObject): TContentParticle;
function FindNext(aDef: TDOMElementDef; ChildIdx: Integer): 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; IsPE := CheckForChar('%');
Map := FDocType.Entities; if IsPE then // [72]
if CheckForChar('%') 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 if FDTDProcessed and not Exists then
Map.SetNamedItem(Entity) 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;