* fcl-xml, making progress with streaming API, implemented IXmlLineInfo interface and fixed reported locations for attributes and their child nodes.

+ Set Name and Value properties for DocumentType nodes.
* Unified HandleEntityStart and HandleEntityEnd code for entity references in content and in attributes.

git-svn-id: trunk@20524 -
This commit is contained in:
sergei 2012-03-16 09:14:47 +00:00
parent c1531f5c12
commit c2a2f88bd4
2 changed files with 81 additions and 19 deletions

View File

@ -268,7 +268,7 @@ type
TLiteralType = (ltPlain, ltPubid, ltEntity); TLiteralType = (ltPlain, ltPubid, ltEntity);
TXMLTextReader = class(TXMLReader) TXMLTextReader = class(TXMLReader, IXmlLineInfo)
private private
FSource: TXMLCharSource; FSource: TXMLCharSource;
FNameTable: THashTable; FNameTable: THashTable;
@ -341,6 +341,9 @@ type
procedure SetNodeInfoWithValue(typ: TXMLNodeType; AName: PHashItem = nil); procedure SetNodeInfoWithValue(typ: TXMLNodeType; AName: PHashItem = nil);
function SetupFakeLF(nextstate: TXMLToken): Boolean; function SetupFakeLF(nextstate: TXMLToken): Boolean;
function AddId(aNodeData: PNodeData): Boolean; function AddId(aNodeData: PNodeData): Boolean;
function QueryInterface(constref iid: TGUID; out obj): HRESULT; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function _AddRef: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
function _Release: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
protected protected
FNesting: Integer; FNesting: Integer;
FCurrNode: PNodeData; FCurrNode: PNodeData;
@ -392,6 +395,7 @@ type
procedure ParseAttribute(ElDef: TElementDecl); procedure ParseAttribute(ElDef: TElementDecl);
function ReadTopLevel: Boolean; function ReadTopLevel: Boolean;
procedure NextAttrValueChunk; procedure NextAttrValueChunk;
function GetHasLineInfo: Boolean;
function GetLineNumber: Integer; function GetLineNumber: Integer;
function GetLinePosition: Integer; function GetLinePosition: Integer;
public public
@ -1000,6 +1004,24 @@ end;
{ TXMLTextReader } { TXMLTextReader }
function TXMLTextReader.QueryInterface(constref iid: TGUID; out obj): HRESULT; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
if GetInterface(iid,obj) then
result := S_OK
else
result:= E_NOINTERFACE;
end;
function TXMLTextReader._AddRef: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
result := -1;
end;
function TXMLTextReader._Release: Longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
begin
result := -1;
end;
procedure TXMLTextReader.ConvertSource(SrcIn: TXMLInputSource; out SrcOut: TXMLCharSource); procedure TXMLTextReader.ConvertSource(SrcIn: TXMLInputSource; out SrcOut: TXMLCharSource);
begin begin
SrcOut := nil; SrcOut := nil;
@ -1746,9 +1768,12 @@ var
start: TObject; start: TObject;
curr: PNodeData; curr: PNodeData;
StartPos: Integer; StartPos: Integer;
StartLoc: TLocation;
entName: PHashItem; entName: PHashItem;
begin begin
SkipQuote(Delim); SkipQuote(Delim);
AttrData^.FLoc2 := FTokenStart;
StartLoc := FTokenStart;
curr := AttrData; curr := AttrData;
FValue.Length := 0; FValue.Length := 0;
StartPos := 0; StartPos := 0;
@ -1767,10 +1792,16 @@ begin
if ((ent = nil) or (not FExpandEntities)) and (FSource.FEntity = start) then if ((ent = nil) or (not FExpandEntities)) and (FSource.FEntity = start) then
begin begin
if FValue.Length > StartPos then if FValue.Length > StartPos then
begin
AllocAttributeValueChunk(curr, StartPos); AllocAttributeValueChunk(curr, StartPos);
curr^.FLoc := StartLoc;
end;
AllocAttributeValueChunk(curr, FValue.Length); AllocAttributeValueChunk(curr, FValue.Length);
curr^.FNodeType := ntEntityReference; curr^.FNodeType := ntEntityReference;
curr^.FQName := entName; curr^.FQName := entName;
StoreLocation(StartLoc);
curr^.FLoc := StartLoc;
Dec(curr^.FLoc.LinePos, FName.Length+1);
end; end;
StartPos := FValue.Length; StartPos := FValue.Length;
if Assigned(ent) then if Assigned(ent) then
@ -1796,7 +1827,10 @@ begin
begin begin
FAttrCleanupFlag := True; FAttrCleanupFlag := True;
if FValue.Length > StartPos then if FValue.Length > StartPos then
begin
AllocAttributeValueChunk(curr, StartPos); AllocAttributeValueChunk(curr, StartPos);
curr^.FLoc := StartLoc;
end;
end; end;
if nonCDATA then if nonCDATA then
BufNormalize(FValue, attrData^.FDenormalized) BufNormalize(FValue, attrData^.FDenormalized)
@ -2193,6 +2227,7 @@ end;
procedure TXMLTextReader.ParseDoctypeDecl; // [28] procedure TXMLTextReader.ParseDoctypeDecl; // [28]
var var
Src: TXMLCharSource; Src: TXMLCharSource;
DTDName: PHashItem;
begin begin
if FState >= rsDTD then if FState >= rsDTD then
FatalError('Markup declaration is not allowed here'); FatalError('Markup declaration is not allowed here');
@ -2208,6 +2243,7 @@ begin
CheckName; CheckName;
SetString(FDocType.FName, FName.Buffer, FName.Length); SetString(FDocType.FName, FName.Buffer, FName.Length);
DTDName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
SkipS(True); SkipS(True);
ParseExternalID(FDocType.FSystemID, FDocType.FPublicID, False); ParseExternalID(FDocType.FSystemID, FDocType.FPublicID, False);
SkipS; SkipS;
@ -2249,7 +2285,9 @@ begin
end; end;
end; end;
FState := rsAfterDTD; FState := rsAfterDTD;
FCurrNode^.FNodeType := ntDocumentType; FValue.Length := 0;
BufAppendString(FValue, FDocType.FInternalSubset);
SetNodeInfoWithValue(ntDocumentType, DTDName);
end; end;
procedure TXMLTextReader.ExpectEq; // [25] procedure TXMLTextReader.ExpectEq; // [25]
@ -2792,6 +2830,8 @@ end;
procedure TXMLTextReader.Close; procedure TXMLTextReader.Close;
begin begin
FReadState := rsClosed; FReadState := rsClosed;
FTokenStart.Line := 0;
FTokenStart.LinePos := 0;
end; end;
function TXMLTextReader.GetAttributeCount: Integer; function TXMLTextReader.GetAttributeCount: Integer;
@ -2882,14 +2922,27 @@ begin
result := FSource.SystemID; result := FSource.SystemID;
end; end;
{ IXmlLineInfo methods }
function TXMLTextReader.GetHasLineInfo: Boolean;
begin
result := True;
end;
function TXMLTextReader.GetLineNumber: Integer; function TXMLTextReader.GetLineNumber: Integer;
begin begin
result := FCurrNode^.FLoc.Line; if (FCurrNode^.FNodeType in [ntElement,ntAttribute]) or (FAttrReadState <> arsNone) then
result := FCurrNode^.FLoc.Line
else
result := FTokenStart.Line;
end; end;
function TXMLTextReader.GetLinePosition: Integer; function TXMLTextReader.GetLinePosition: Integer;
begin begin
result := FCurrNode^.FLoc.LinePos; if (FCurrNode^.FNodeType in [ntElement,ntAttribute]) or (FAttrReadState <> arsNone) then
result := FCurrNode^.FLoc.LinePos
else
result := FTokenStart.LinePos;
end; end;
function TXMLTextReader.LookupNamespace(const APrefix: XMLString): XMLString; function TXMLTextReader.LookupNamespace(const APrefix: XMLString): XMLString;
@ -2999,6 +3052,7 @@ begin
end; end;
FCurrNode := @FNodeStack[FNesting+FAttrCount+1]; FCurrNode := @FNodeStack[FNesting+FAttrCount+1];
StoreLocation(FCurrNode^.FLoc);
FValue.Length := 0; FValue.Length := 0;
if FAttrReadState = arsText then if FAttrReadState = arsText then
repeat repeat
@ -3033,19 +3087,12 @@ begin
if tok = arsEntity then if tok = arsEntity then
begin begin
FCurrNode^.FNodeType := ntEntityReference; HandleEntityStart;
FCurrNode^.FQName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
FCurrNode^.FValueStart := nil;
FCurrNode^.FValueLength := 0;
FCurrNode^.FValueStr := '';
FAttrReadState := arsText; FAttrReadState := arsText;
end end
else if tok = arsEntityEnd then else if tok = arsEntityEnd then
begin begin
ContextPop(True); HandleEntityEnd;
Dec(FNesting);
FCurrNode := @FNodeStack[FNesting+FAttrCount+1];
FCurrNode^.FNodeType := ntEndEntity;
FAttrReadState := arsText; FAttrReadState := arsText;
end; end;
end; end;
@ -3219,21 +3266,26 @@ end;
procedure TXMLTextReader.HandleEntityStart; procedure TXMLTextReader.HandleEntityStart;
begin begin
FCurrNode := @FNodeStack[FNesting]; FCurrNode := @FNodeStack[FNesting+(FAttrCount+1)*ord(FAttrReadState<>arsNone)];
FCurrNode^.FNodeType := ntEntityReference; FCurrNode^.FNodeType := ntEntityReference;
FCurrNode^.FQName := FNameTable.FindOrAdd(FName.Buffer, FName.Length); FCurrNode^.FQName := FNameTable.FindOrAdd(FName.Buffer, FName.Length);
FCurrNode^.FColonPos := -1;
FCurrNode^.FValueStart := nil; FCurrNode^.FValueStart := nil;
FCurrNode^.FValueLength := 0; FCurrNode^.FValueLength := 0;
FCurrNode^.FValueStr := '';
StoreLocation(FCurrNode^.FLoc);
{ point past '&' to first char of entity name }
Dec(FCurrNode^.FLoc.LinePos, FName.Length+1);
end; end;
procedure TXMLTextReader.HandleEntityEnd; procedure TXMLTextReader.HandleEntityEnd;
begin begin
ContextPop(True); ContextPop(True);
if FNesting > 0 then Dec(FNesting); if FNesting > 0 then Dec(FNesting);
FCurrNode := @FNodeStack[FNesting]; FCurrNode := @FNodeStack[FNesting+(FAttrCount+1)*ord(FAttrReadState<>arsNone)];
FCurrNode^.FNodeType := ntEndEntity; FCurrNode^.FNodeType := ntEndEntity;
// TODO: other properties of FCurrNode { point to trailing ';' }
FNext := xtText; Inc(FCurrNode^.FLoc.LinePos, Length(FCurrNode^.FQName^.Key));
end; end;
procedure TXMLTextReader.ResolveEntity; procedure TXMLTextReader.ResolveEntity;
@ -3252,6 +3304,7 @@ begin
if n <> FCurrNode then if n <> FCurrNode then
n^ := FCurrNode^; n^ := FCurrNode^;
ent := nil;
if Assigned(FDocType) then if Assigned(FDocType) then
ent := FDocType.Entities.Get(PWideChar(n^.FQName^.Key),Length(n^.FQName^.Key)) as TEntityDecl; ent := FDocType.Entities.Get(PWideChar(n^.FQName^.Key),Length(n^.FQName^.Key)) as TEntityDecl;
if ent = nil then if ent = nil then
@ -3754,6 +3807,8 @@ begin
FCurrNode := @FNodeStack[FNesting]; // move off the possible child FCurrNode := @FNodeStack[FNesting]; // move off the possible child
FCurrNode^.FNodeType := ntEndElement; FCurrNode^.FNodeType := ntEndElement;
Inc(FTokenStart.LinePos, 2); // move over '</' chars
FCurrNode^.FLoc := FTokenStart;
ElName := FCurrNode^.FQName; ElName := FCurrNode^.FQName;
CheckName; CheckName;
@ -3766,7 +3821,6 @@ begin
SkipS; SkipS;
ExpectChar('>'); ExpectChar('>');
end; end;
Inc(FTokenStart.LinePos, 2); // move over '</' chars
FNext := xtPopElement; FNext := xtPopElement;
end; end;
@ -3822,7 +3876,6 @@ begin
ExpectEq; ExpectEq;
ExpectAttValue(attrData, Assigned(AttDef) and (AttDef.DataType <> dtCDATA)); ExpectAttValue(attrData, Assigned(AttDef) and (AttDef.DataType <> dtCDATA));
attrData^.FLoc2 := FTokenStart;
if Assigned(attrData^.FNsUri) then if Assigned(attrData^.FNsUri) then
begin begin

View File

@ -147,6 +147,15 @@ type
LinePos: Integer; LinePos: Integer;
end; end;
IXmlLineInfo = interface(IInterface)['{FD0A892B-B26C-4954-9995-103B2A9D178A}']
function GetHasLineInfo: Boolean;
function GetLineNumber: Integer;
function GetLinePosition: Integer;
property HasLineInfo: Boolean read GetHasLineInfo;
property LineNumber: Integer read GetLineNumber;
property LinePosition: Integer read GetLinePosition;
end;
{ generic node info record, shared between DOM and reader } { generic node info record, shared between DOM and reader }
PNodeData = ^TNodeData; PNodeData = ^TNodeData;