* xmlread.pp: separated DOM-specific code into DoStartElement(); introduced FNameTable.

git-svn-id: trunk@16270 -
This commit is contained in:
sergei 2010-10-31 02:23:42 +00:00
parent 4e39959ca1
commit b066395a2b

View File

@ -280,6 +280,7 @@ type
TXMLReader = class TXMLReader = class
private private
FSource: TXMLCharSource; FSource: TXMLCharSource;
FNameTable: THashTable;
FCtrl: TDOMParser; FCtrl: TDOMParser;
FXML11: Boolean; FXML11: Boolean;
FState: TXMLReadState; FState: TXMLReadState;
@ -394,6 +395,7 @@ type
procedure ParseMarkupDecl; // [29] procedure ParseMarkupDecl; // [29]
procedure ParseStartTag; // [39] procedure ParseStartTag; // [39]
procedure ParseEndTag; // [42] procedure ParseEndTag; // [42]
procedure DoStartElement;
procedure DoEndElement; procedure DoEndElement;
procedure ParseAttribute(ElDef: TElementDecl); procedure ParseAttribute(ElDef: TElementDecl);
procedure ParseContent; // [43] procedure ParseContent; // [43]
@ -1313,8 +1315,8 @@ begin
FStdPrefix_xml := FNSHelper.GetPrefix(@PrefixDefault, 3); FStdPrefix_xml := FNSHelper.GetPrefix(@PrefixDefault, 3);
FStdPrefix_xmlns := FNSHelper.GetPrefix(@PrefixDefault, 5); FStdPrefix_xmlns := FNSHelper.GetPrefix(@PrefixDefault, 5);
FStdUri_xmlns := doc.Names.FindOrAdd(PWideChar(stduri_xmlns), Length(stduri_xmlns)); FStdUri_xmlns := FNameTable.FindOrAdd(PWideChar(stduri_xmlns), Length(stduri_xmlns));
FStdUri_xml := doc.Names.FindOrAdd(PWideChar(stduri_xml), Length(stduri_xml)); FStdUri_xml := FNameTable.FindOrAdd(PWideChar(stduri_xml), Length(stduri_xml));
end; end;
end; end;
@ -1322,6 +1324,7 @@ procedure TXMLReader.ProcessXML(ASource: TXMLCharSource);
begin begin
doc := TXMLDocument.Create; doc := TXMLDocument.Create;
doc.documentURI := ASource.SystemID; // TODO: to be changed to URI or BaseURI doc.documentURI := ASource.SystemID; // TODO: to be changed to URI or BaseURI
FNameTable := doc.Names;
FState := rsProlog; FState := rsProlog;
FNesting := 0; FNesting := 0;
FCurrNode := @FNodeStack[0]; FCurrNode := @FNodeStack[0];
@ -1343,6 +1346,7 @@ end;
procedure TXMLReader.ProcessFragment(ASource: TXMLCharSource; AOwner: TDOMNode); procedure TXMLReader.ProcessFragment(ASource: TXMLCharSource; AOwner: TDOMNode);
begin begin
doc := AOwner.OwnerDocument; doc := AOwner.OwnerDocument;
FNameTable := doc.Names;
FState := rsRoot; FState := rsRoot;
FNesting := 0; FNesting := 0;
FCurrNode := @FNodeStack[0]; FCurrNode := @FNodeStack[0];
@ -1926,7 +1930,7 @@ begin
if not SkipUntilSeq(GT_Delim, '?') then if not SkipUntilSeq(GT_Delim, '?') then
FatalError('Unterminated processing instruction', -1); FatalError('Unterminated processing instruction', -1);
SetNodeInfoWithValue(ntProcessingInstruction, SetNodeInfoWithValue(ntProcessingInstruction,
doc.Names.FindOrAdd(FName.Buffer, FName.Length)); FNameTable.FindOrAdd(FName.Buffer, FName.Length));
end; end;
procedure TXMLReader.CreatePINode; procedure TXMLReader.CreatePINode;
@ -2165,7 +2169,7 @@ var
p: PHashItem; p: PHashItem;
begin begin
CheckName; CheckName;
p := doc.Names.FindOrAdd(FName.Buffer, FName.Length); p := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
Result := TElementDecl(p^.Data); Result := TElementDecl(p^.Data);
if Result = nil then if Result = nil then
begin begin
@ -2343,7 +2347,7 @@ begin
begin begin
CheckName; CheckName;
ExpectWhitespace; ExpectWhitespace;
attrName := doc.Names.FindOrAdd(FName.Buffer, FName.Length); attrName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
AttDef := TAttributeDef.Create(attrName, FColonPos); AttDef := TAttributeDef.Create(attrName, FColonPos);
try try
AttDef.ExternallyDeclared := FSource.DTDSubsetType <> dsInternal; AttDef.ExternallyDeclared := FSource.DTDSubsetType <> dsInternal;
@ -2656,6 +2660,7 @@ end;
procedure TXMLReader.ProcessDTD(ASource: TXMLCharSource); procedure TXMLReader.ProcessDTD(ASource: TXMLCharSource);
begin begin
doc := TXMLDocument.Create; doc := TXMLDocument.Create;
FNameTable := doc.Names;
FDocType := TDOMDocumentTypeEx.Create(doc); FDocType := TDOMDocumentTypeEx.Create(doc);
// TODO: DTD labeled version 1.1 will be rejected - must set FXML11 flag // TODO: DTD labeled version 1.1 will be rejected - must set FXML11 flag
doc.AppendChild(FDocType); doc.AppendChild(FDocType);
@ -2675,6 +2680,28 @@ begin
cur.AppendChild(doc.CreateEntityReference(s)); cur.AppendChild(doc.CreateEntityReference(s));
end; end;
procedure TXMLReader.DoStartElement;
var
NewElem: TDOMElement;
Attr: TDOMAttr;
i: Integer;
begin
with FCurrNode^.FQName^ do
NewElem := doc.CreateElementBuf(PWideChar(Key), Length(Key));
FCursorStack[FNesting-1].InternalAppend(NewElem);
FCursorStack[FNesting] := NewElem;
if Assigned(FCurrNode^.FNsUri) then
NewElem.SetNSI(FCurrNode^.FNsUri^.Key, FCurrNode^.FColonPos+1);
for i := 1 to FAttrCount do
begin
Attr := LoadAttribute(doc, @FNodeStack[FNesting+i]);
NewElem.SetAttributeNode(Attr);
// Attach element to ID map entry if necessary
if Assigned(FNodeStack[FNesting+i].FIDEntry) then
FNodeStack[FNesting+i].FIDEntry^.Data := NewElem;
end;
end;
// The code below does the bulk of the parsing, and must be as fast as possible. // The code below does the bulk of the parsing, and must be as fast as possible.
// To minimize CPU cache effects, methods from different classes are kept together // To minimize CPU cache effects, methods from different classes are kept together
@ -2743,6 +2770,8 @@ begin
CreatePINode; CreatePINode;
xtComment: xtComment:
DoComment(FCurrNode^.FValueStart, FCurrNode^.FValueLength); DoComment(FCurrNode^.FValueStart, FCurrNode^.FValueLength);
xtElement:
DoStartElement;
xtEndElement: xtEndElement:
DoEndElement; DoEndElement;
xtDoctype: xtDoctype:
@ -2942,13 +2971,10 @@ end;
// Element name already in FNameBuffer // Element name already in FNameBuffer
procedure TXMLReader.ParseStartTag; // [39] [40] [44] procedure TXMLReader.ParseStartTag; // [39] [40] [44]
var var
NewElem: TDOMElement;
Attr: TDOMAttr;
ElDef: TElementDecl; ElDef: TElementDecl;
IsEmpty: Boolean; IsEmpty: Boolean;
ElName: PHashItem; ElName: PHashItem;
b: TBinding; b: TBinding;
i: Integer;
begin begin
if FState > rsRoot then if FState > rsRoot then
FatalError('Only one top-level element allowed', FName.Length) FatalError('Only one top-level element allowed', FName.Length)
@ -2962,11 +2988,8 @@ begin
// we're about to process a new set of attributes // we're about to process a new set of attributes
Inc(FAttrTag); Inc(FAttrTag);
NewElem := doc.CreateElementBuf(FName.Buffer, FName.Length);
FCursorStack[FNesting].InternalAppend(NewElem);
// Remember the hash entry, we'll need it often // Remember the hash entry, we'll need it often
ElName := NewElem.NSI.QName; ElName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
// Find declaration for this element // Find declaration for this element
ElDef := TElementDecl(ElName^.Data); ElDef := TElementDecl(ElName^.Data);
@ -2982,7 +3005,6 @@ begin
FPrefixedAttrs := 0; FPrefixedAttrs := 0;
FSpecifiedAttrs := 0; FSpecifiedAttrs := 0;
PushVC(ElDef); // this increases FNesting PushVC(ElDef); // this increases FNesting
FCursorStack[FNesting] := NewElem;
FCurrNode^.FQName := ElName; FCurrNode^.FQName := ElName;
FCurrNode^.FNodeType := ntElement; FCurrNode^.FNodeType := ntElement;
@ -3031,28 +3053,15 @@ begin
FTokenStart := FCurrNode^.FLoc; FTokenStart := FCurrNode^.FLoc;
FatalError('Unbound element name prefix "%s"', [FCurrNode^.FPrefix^.Key],-1); FatalError('Unbound element name prefix "%s"', [FCurrNode^.FPrefix^.Key],-1);
end; end;
FCurrNode^.FNsUri := doc.Names.FindOrAdd(PWideChar(b.uri), Length(b.uri)); FCurrNode^.FNsUri := FNameTable.FindOrAdd(PWideChar(b.uri), Length(b.uri));
NewElem.SetNSI(b.uri, FCurrNode^.FColonPos+1);
end end
else else
begin begin
b := FNSHelper.DefaultNSBinding; b := FNSHelper.DefaultNSBinding;
if Assigned(b) then if Assigned(b) then
begin FCurrNode^.FNsUri := FNameTable.FindOrAdd(PWideChar(b.uri), Length(b.uri));
FCurrNode^.FNsUri := doc.Names.FindOrAdd(PWideChar(b.uri), Length(b.uri));
NewElem.SetNSI(b.uri, FCurrNode^.FColonPos+1);
end; end;
end; end;
end;
for i := 1 to FAttrCount do
begin
Attr := LoadAttribute(doc, @FNodeStack[FNesting+i]);
NewElem.SetAttributeNode(Attr);
// Attach element to ID map entry if necessary
if Assigned(FNodeStack[FNesting+i].FIDEntry) then
FNodeStack[FNesting+i].FIDEntry^.Data := NewElem;
end;
if not IsEmpty then if not IsEmpty then
begin begin
@ -3119,7 +3128,7 @@ end;
begin begin
CheckName; CheckName;
attrName := doc.Names.FindOrAdd(FName.Buffer, FName.Length); attrName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
attrData := AllocAttributeData(attrName); attrData := AllocAttributeData(attrName);
attrData^.FColonPos := FColonPos; attrData^.FColonPos := FColonPos;
StoreLocation(attrData^.FLoc); StoreLocation(attrData^.FLoc);
@ -3264,7 +3273,7 @@ function TXMLReader.AddBinding(attrData: PNodeData): Boolean;
var var
nsUri, Pfx: PHashItem; nsUri, Pfx: PHashItem;
begin begin
nsUri := doc.Names.FindOrAdd(PWideChar(attrData^.FValueStr), Length(attrData^.FValueStr)); nsUri := FNameTable.FindOrAdd(PWideChar(attrData^.FValueStr), Length(attrData^.FValueStr));
if attrData^.FColonPos > 0 then if attrData^.FColonPos > 0 then
Pfx := FNSHelper.GetPrefix(@attrData^.FQName^.key[7], Length(attrData^.FQName^.key)-6) Pfx := FNSHelper.GetPrefix(@attrData^.FQName^.key[7], Length(attrData^.FQName^.key)-6)
else else
@ -3320,7 +3329,7 @@ begin
if FNsAttHash.Locate(@b.uri, @AttrName^.Key[J], Length(AttrName^.Key) - J+1) then if FNsAttHash.Locate(@b.uri, @AttrName^.Key[J], Length(AttrName^.Key) - J+1) then
DoErrorPos(esFatal, 'Duplicate prefixed attribute', attrData^.FLoc); DoErrorPos(esFatal, 'Duplicate prefixed attribute', attrData^.FLoc);
attrData^.FNsUri := doc.Names.FindOrAdd(PWideChar(b.uri), Length(b.uri)); attrData^.FNsUri := FNameTable.FindOrAdd(PWideChar(b.uri), Length(b.uri));
end; end;
end; end;