* fcl-xml, making progress with streaming API, moved DOM-dependent stuff from TXMLTextReader to the TLoader helper object. Now TXMLTextReader class is almost free from direct DOM dependencies (indirect ones like TDOMParser are still present, also entity handling is still intertwined too closely).

git-svn-id: trunk@20467 -
This commit is contained in:
sergei 2012-03-03 12:26:52 +00:00
parent af66d92faf
commit a417e9d0b6

View File

@ -276,6 +276,7 @@ type
FNameTable: THashTable; FNameTable: THashTable;
FCtrl: TDOMParser; FCtrl: TDOMParser;
FXML11: Boolean; FXML11: Boolean;
FNameTableOwned: Boolean;
FState: TXMLReadState; FState: TXMLReadState;
FHavePERefs: Boolean; FHavePERefs: Boolean;
FInsideDecl: Boolean; FInsideDecl: Boolean;
@ -321,7 +322,6 @@ type
procedure SetEOFState; procedure SetEOFState;
procedure SkipQuote(out Delim: WideChar; required: Boolean = True); procedure SkipQuote(out Delim: WideChar; required: Boolean = True);
procedure Initialize(ASource: TXMLCharSource); procedure Initialize(ASource: TXMLCharSource);
procedure NSPrepare;
procedure EntityToSource(AEntity: TEntityDecl; out Src: TXMLCharSource); procedure EntityToSource(AEntity: TEntityDecl; out Src: TXMLCharSource);
function ContextPush(AEntity: TEntityDecl): Boolean; function ContextPush(AEntity: TEntityDecl): Boolean;
function ContextPop(Forced: Boolean = False): Boolean; function ContextPop(Forced: Boolean = False): Boolean;
@ -383,7 +383,6 @@ type
procedure ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean); // [10] procedure ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean); // [10]
procedure ParseComment(discard: Boolean); // [15] procedure ParseComment(discard: Boolean); // [15]
procedure ParsePI; // [16] procedure ParsePI; // [16]
function CreatePINode: TDOMNode;
procedure ParseXmlOrTextDecl(TextDecl: Boolean); procedure ParseXmlOrTextDecl(TextDecl: Boolean);
procedure ExpectEq; procedure ExpectEq;
procedure ParseDoctypeDecl; // [28] procedure ParseDoctypeDecl; // [28]
@ -391,12 +390,10 @@ type
procedure ParseIgnoreSection; procedure ParseIgnoreSection;
procedure ParseStartTag; // [39] procedure ParseStartTag; // [39]
procedure ParseEndTag; // [42] procedure ParseEndTag; // [42]
function DoStartElement: TDOMElement;
procedure HandleEntityStart; procedure HandleEntityStart;
procedure HandleEntityEnd; procedure HandleEntityEnd;
procedure DoStartEntity; procedure DoStartEntity;
procedure ParseAttribute(ElDef: TElementDecl); procedure ParseAttribute(ElDef: TElementDecl);
procedure ParseContent(cursor: TDOMNode_WithChildren); // [43]
function ReadTopLevel: Boolean; function ReadTopLevel: Boolean;
procedure NextAttrValueChunk; procedure NextAttrValueChunk;
public public
@ -452,16 +449,32 @@ type
procedure ValidationErrorWithName(const Msg: string; LineOffs: Integer = -1); procedure ValidationErrorWithName(const Msg: string; LineOffs: Integer = -1);
procedure DTDReloadHook; procedure DTDReloadHook;
procedure ConvertSource(SrcIn: TXMLInputSource; out SrcOut: TXMLCharSource); procedure ConvertSource(SrcIn: TXMLInputSource; out SrcOut: TXMLCharSource);
function DoCDSect(ch: PWideChar; Count: Integer): TDOMNode;
procedure DoNotationDecl(const aName, aPubID, aSysID: XMLString); procedure DoNotationDecl(const aName, aPubID, aSysID: XMLString);
procedure SetOptions(AParser: TDOMParser);
public public
doc: TDOMDocument; { Entity loading still needs to reference the document, at least as an opaque pointer }
FDoc: TObject;
constructor Create; overload; constructor Create; overload;
constructor Create(AParser: TDOMParser); overload; constructor Create(ASrc: TXMLCharSource; ANameTable: THashTable); overload;
constructor Create(ASrc: TXMLCharSource; AParent: TXMLTextReader); overload;
constructor Create(const uri: XMLString; ANameTable: THashTable; AParser: TDOMParser); overload;
constructor Create(ASrc: TXMLInputSource; ANameTable: THashTable; AParser: TDOMParser); overload;
destructor Destroy; override; destructor Destroy; override;
procedure ProcessXML(ASource: TXMLCharSource); // [1] procedure AfterConstruction; override;
procedure ProcessFragment(ASource: TXMLCharSource; AOwner: TDOMNode); end;
procedure ProcessDTD(ASource: TXMLCharSource); // ([29])
TLoader = object
doc: TDOMDocument;
reader: TXMLTextReader;
function DoStartElement: TDOMElement;
function DoCDSect(ch: PWideChar; Count: Integer): TDOMNode;
function CreatePINode: TDOMNode;
procedure ParseContent(cursor: TDOMNode_WithChildren);
procedure ProcessXML(ADoc: TDOMDocument; AReader: TXMLTextReader);
procedure ProcessFragment(AOwner: TDOMNode; AReader: TXMLTextReader);
procedure ProcessDTD(ADoc: TDOMDocument; AReader: TXMLTextReader);
procedure ProcessEntity(ADoc: TObject; AReader: TXMLTextReader; AEntity: TEntityDecl);
end; end;
const const
@ -564,41 +577,39 @@ end;
procedure TDOMParser.Parse(Src: TXMLInputSource; out ADoc: TXMLDocument); procedure TDOMParser.Parse(Src: TXMLInputSource; out ADoc: TXMLDocument);
var var
InputSrc: TXMLCharSource; Reader: TXMLTextReader;
ldr: TLoader;
begin begin
with TXMLTextReader.Create(Self) do ADoc := TXMLDocument.Create;
Reader := TXMLTextReader.Create(Src, ADoc.Names, Self);
try try
ConvertSource(Src, InputSrc); // handles 'no-input-specified' case ldr.ProcessXML(ADoc, Reader);
ProcessXML(InputSrc)
finally finally
ADoc := TXMLDocument(doc); Reader.Free;
Free;
end; end;
end; end;
procedure TDOMParser.ParseUri(const URI: XMLString; out ADoc: TXMLDocument); procedure TDOMParser.ParseUri(const URI: XMLString; out ADoc: TXMLDocument);
var var
Src: TXMLCharSource; Reader: TXMLTextReader;
ldr: TLoader;
begin begin
ADoc := nil; ADoc := TXMLDocument.Create;
with TXMLTextReader.Create(Self) do Reader := TXMLTextReader.Create(URI, ADoc.Names, Self);
try try
if ResolveResource(URI, '', '', Src) then ldr.ProcessXML(ADoc, Reader)
ProcessXML(Src)
else
DoErrorPos(esFatal, 'The specified URI could not be resolved', NullLocation);
finally finally
ADoc := TXMLDocument(doc); Reader.Free;
Free;
end; end;
end; end;
function TDOMParser.ParseWithContext(Src: TXMLInputSource; function TDOMParser.ParseWithContext(Src: TXMLInputSource;
Context: TDOMNode; Action: TXMLContextAction): TDOMNode; Context: TDOMNode; Action: TXMLContextAction): TDOMNode;
var var
InputSrc: TXMLCharSource;
Frag: TDOMDocumentFragment; Frag: TDOMDocumentFragment;
node: TDOMNode; node: TDOMNode;
reader: TXMLTextReader;
ldr: TLoader;
begin begin
if Action in [xaInsertBefore, xaInsertAfter, xaReplace] then if Action in [xaInsertBefore, xaInsertAfter, xaReplace] then
node := Context.ParentNode node := Context.ParentNode
@ -611,12 +622,11 @@ begin
if not (node.NodeType in [ELEMENT_NODE, DOCUMENT_FRAGMENT_NODE]) then if not (node.NodeType in [ELEMENT_NODE, DOCUMENT_FRAGMENT_NODE]) then
raise EDOMHierarchyRequest.Create('DOMParser.ParseWithContext'); raise EDOMHierarchyRequest.Create('DOMParser.ParseWithContext');
with TXMLTextReader.Create(Self) do reader := TXMLTextReader.Create(Src, Context.OwnerDocument.Names, Self);
try try
ConvertSource(Src, InputSrc); // handles 'no-input-specified' case
Frag := Context.OwnerDocument.CreateDocumentFragment; Frag := Context.OwnerDocument.CreateDocumentFragment;
try try
ProcessFragment(InputSrc, Frag); ldr.ProcessFragment(Frag, reader);
Result := Frag.FirstChild; Result := Frag.FirstChild;
case Action of case Action of
xaAppendAsChildren: Context.AppendChild(Frag); xaAppendAsChildren: Context.AppendChild(Frag);
@ -633,7 +643,7 @@ begin
Frag.Free; Frag.Free;
end; end;
finally finally
Free; reader.Free;
end; end;
end; end;
@ -1275,9 +1285,8 @@ begin
SetLength(FValidators, 16); SetLength(FValidators, 16);
end; end;
constructor TXMLTextReader.Create(AParser: TDOMParser); procedure TXMLTextReader.SetOptions(AParser: TDOMParser);
begin begin
Create;
FCtrl := AParser; FCtrl := AParser;
if FCtrl = nil then if FCtrl = nil then
Exit; Exit;
@ -1293,6 +1302,51 @@ begin
FMaxChars := FCtrl.Options.MaxChars; FMaxChars := FCtrl.Options.MaxChars;
end; end;
constructor TXMLTextReader.Create(ASrc: TXMLInputSource; ANameTable: THashTable; AParser: TDOMParser);
var
InputSrc: TXMLCharSource;
begin
Create;
SetOptions(AParser);
FNameTable := ANameTable;
ConvertSource(ASrc, InputSrc);
FSource := InputSrc;
FSource.FReader := Self;
end;
constructor TXMLTextReader.Create(const uri: XMLString; ANameTable: THashTable; AParser: TDOMParser);
begin
Create;
SetOptions(AParser);
FNameTable := ANameTable;
{ TODO: should not open file in ResolveResource, but do it when Read() is called
for the first time }
if ResolveResource(uri, '', '', FSource) then
FSource.FReader := Self
else
DoErrorPos(esFatal, 'The specified URI could not be resolved', NullLocation);
end;
constructor TXMLTextReader.Create(ASrc: TXMLCharSource; ANameTable: THashTable);
begin
if ANameTable = nil then
begin
ANameTable := THashTable.Create(256, True);
FNameTableOwned := True;
end;
FNameTable := ANameTable;
Create;
FSource := ASrc;
FSource.FReader := Self;
end;
constructor TXMLTextReader.Create(ASrc: TXMLCharSource; AParent: TXMLTextReader);
begin
Create(ASrc, AParent.FNameTable);
SetOptions(AParent.FCtrl);
end;
destructor TXMLTextReader.Destroy; destructor TXMLTextReader.Destroy;
var var
i: Integer; i: Integer;
@ -1314,16 +1368,17 @@ begin
FIDMap.Free; FIDMap.Free;
FForwardRefs.Free; FForwardRefs.Free;
FAttrChunks.Free; FAttrChunks.Free;
if doc = nil then if FNameTableOwned then
FNameTable.Free; FNameTable.Free;
inherited Destroy; inherited Destroy;
end; end;
{ Must be executed after doc has been set. procedure TXMLTextReader.AfterConstruction;
After introducing own NameTable, merge this into constructor }
procedure TXMLTextReader.NSPrepare;
begin begin
FNesting := 0;
FValidatorNesting := 0;
FCurrNode := @FNodeStack[0];
if FNamespaces then if FNamespaces then
begin begin
FNSHelper := TNSSupport.Create; FNSHelper := TNSSupport.Create;
@ -1336,63 +1391,165 @@ begin
end; end;
end; end;
procedure TXMLTextReader.ProcessXML(ASource: TXMLCharSource); procedure TLoader.ProcessXML(ADoc: TDOMDocument; AReader: TXMLTextReader);
begin begin
doc := TXMLDocument.Create; doc := ADoc;
doc.documentURI := ASource.SystemID; // TODO: to be changed to URI or BaseURI reader := AReader;
FNameTable := doc.Names; reader.FDoc := ADoc;
FState := rsProlog; doc.documentURI := reader.BaseURI;
FNesting := 0; reader.FState := rsProlog;
FValidatorNesting := 0; reader.FFragmentMode := False;
FCurrNode := @FNodeStack[0];
FFragmentMode := False;
NSPrepare;
Initialize(ASource);
if FSource.FXMLVersion <> xmlVersionUnknown then
TDOMTopNodeEx(TDOMNode(doc)).FXMLVersion := FSource.FXMLVersion;
TDOMTopNodeEx(TDOMNode(doc)).FXMLEncoding := FSource.FXMLEncoding;
doc.XMLStandalone := FStandalone;
FNext := xtText;
ParseContent(doc); ParseContent(doc);
doc.XMLStandalone := reader.FStandalone;
if FValidate then if reader.FValidate then
ValidateIdRefs; reader.ValidateIdRefs;
doc.IDs := FIDMap; doc.IDs := reader.FIDMap;
FIDMap := nil; reader.FIDMap := nil;
end; end;
procedure TXMLTextReader.ProcessFragment(ASource: TXMLCharSource; AOwner: TDOMNode); procedure TLoader.ProcessFragment(AOwner: TDOMNode; AReader: TXMLTextReader);
var var
DoctypeNode: TDOMDocumentTypeEx; DoctypeNode: TDOMDocumentTypeEx;
begin begin
doc := AOwner.OwnerDocument; doc := AOwner.OwnerDocument;
FNameTable := doc.Names; reader := AReader;
FState := rsRoot; reader.FDoc := doc;
FNesting := 0; reader.FState := rsRoot;
FValidatorNesting := 0; reader.FFragmentMode := True;
FCurrNode := @FNodeStack[0]; reader.FXML11 := doc.XMLVersion = '1.1';
FFragmentMode := True; DoctypeNode := TDOMDocumentTypeEx(doc.DocType);
FXML11 := doc.XMLVersion = '1.1'; if Assigned(DoctypeNode) then
NSPrepare; reader.FDocType := DocTypeNode.FModel.Reference;
Initialize(ASource);
{ Get doctype from the owner's document, but only if it is not already assigned
(It is set directly when parsing children of an Entity, see LoadEntity procedure) }
if FDocType = nil then
begin
DoctypeNode := TDOMDocumentTypeEx(doc.DocType);
if Assigned(DoctypeNode) then
FDocType := DocTypeNode.FModel.Reference;
end;
if AOwner is TDOMEntity then
begin
TDOMTopNodeEx(AOwner).FXMLVersion := FSource.FXMLVersion;
TDOMTopNodeEx(AOwner).FXMLEncoding := FSource.FXMLEncoding;
end;
FNext := xtText;
ParseContent(aOwner as TDOMNode_WithChildren); ParseContent(aOwner as TDOMNode_WithChildren);
end; end;
procedure TLoader.ProcessEntity(ADoc: TObject; AReader: TXMLTextReader; AEntity: TEntityDecl);
var
DoctypeNode: TDOMDocumentType;
Ent: TDOMEntityEx;
src: TXMLCharSource;
begin
DoctypeNode := TDOMDocument(ADoc).DocType;
if DoctypeNode = nil then
Exit;
Ent := TDOMEntityEx(DocTypeNode.Entities.GetNamedItem(AEntity.FName));
if Ent = nil then
Exit;
AReader.EntityToSource(AEntity, Src);
if Src = nil then
Exit;
reader := TXMLTextReader.Create(Src, AReader);
try
Ent.SetReadOnly(False);
ProcessFragment(Ent, reader);
AEntity.FResolved := True;
finally
reader.Free;
AEntity.FOnStack := False;
Ent.SetReadOnly(True);
end;
end;
procedure TLoader.ParseContent(cursor: TDOMNode_WithChildren);
var
element: TDOMElement;
begin
if reader.ReadState = rsInitial then
begin
reader.Read;
if cursor is TDOMNode_TopLevel then
begin
if reader.FSource.FXMLVersion <> xmlVersionUnknown then
TDOMTopNodeEx(cursor).FXMLVersion := reader.FSource.FXMLVersion;
TDOMTopNodeEx(cursor).FXMLEncoding := reader.FSource.FXMLEncoding;
end;
end;
with reader do
repeat
if FValidate then
ValidateCurrentNode;
case FCurrNode^.FNodeType of
ntText:
cursor.InternalAppend(doc.CreateTextNodeBuf(FValue.Buffer, FValue.Length, False));
ntWhitespace, ntSignificantWhitespace:
if FPreserveWhitespace then
cursor.InternalAppend(doc.CreateTextNodeBuf(FValue.Buffer, FValue.Length, FCurrNode^.FNodeType = ntWhitespace));
ntCDATA:
cursor.InternalAppend(DoCDSect(FValue.Buffer, FValue.Length));
ntProcessingInstruction:
cursor.InternalAppend(CreatePINode);
ntComment:
if not FIgnoreComments then
cursor.InternalAppend(doc.CreateCommentBuf(FCurrNode^.FValueStart, FCurrNode^.FValueLength));
ntElement:
begin
element := DoStartElement;
cursor.InternalAppend(element);
cursor := element;
end;
ntEndElement:
cursor := TDOMNode_WithChildren(cursor.ParentNode);
ntDocumentType:
if not FCanonical then
cursor.InternalAppend(TDOMDocumentType.Create(doc, FDocType));
ntEntityReference:
cursor.InternalAppend(doc.CreateEntityReference(FCurrNode^.FQName^.Key));
end;
until not Read;
end;
function TLoader.DoStartElement: TDOMElement;
var
Attr: TDOMAttr;
i: Integer;
begin
with reader.FCurrNode^ do
begin
Result := doc.CreateElementBuf(PWideChar(FQName^.Key), Length(FQName^.Key));
if Assigned(FNsUri) then
Result.SetNSI(FNsUri^.Key, FColonPos+1);
end;
for i := 1 to reader.FAttrCount do
begin
Attr := LoadAttribute(doc, @reader.FNodeStack[reader.FNesting+i]);
Result.SetAttributeNode(Attr);
// Attach element to ID map entry if necessary
if Assigned(reader.FNodeStack[reader.FNesting+i].FIDEntry) then
reader.FNodeStack[reader.FNesting+i].FIDEntry^.Data := Result;
end;
end;
function TLoader.CreatePINode: TDOMNode;
var
NameStr, ValueStr: DOMString;
begin
SetString(NameStr, reader.FName.Buffer, reader.FName.Length);
SetString(ValueStr, reader.FValue.Buffer, reader.FValue.Length);
result := Doc.CreateProcessingInstruction(NameStr, ValueStr);
end;
function TLoader.DoCDSect(ch: PWideChar; Count: Integer): TDOMNode;
var
s: XMLString;
begin
SetString(s, ch, Count);
result := doc.CreateCDATASection(s);
end;
function TXMLTextReader.CheckName(aFlags: TCheckNameFlags): Boolean; function TXMLTextReader.CheckName(aFlags: TCheckNameFlags): Boolean;
var var
p: PWideChar; p: PWideChar;
@ -1922,15 +2079,6 @@ begin
FNameTable.FindOrAdd(FName.Buffer, FName.Length)); FNameTable.FindOrAdd(FName.Buffer, FName.Length));
end; end;
function TXMLTextReader.CreatePINode: TDOMNode;
var
NameStr, ValueStr: DOMString;
begin
SetString(NameStr, FName.Buffer, FName.Length);
SetString(ValueStr, FValue.Buffer, FValue.Length);
result := Doc.CreateProcessingInstruction(NameStr, ValueStr);
end;
const const
vers: array[Boolean] of TXMLVersion = (xmlVersion10, xmlVersion11); vers: array[Boolean] of TXMLVersion = (xmlVersion10, xmlVersion11);
@ -2550,8 +2698,6 @@ begin
if FSource.FBuf^ = '?' then if FSource.FBuf^ = '?' then
begin begin
ParsePI; ParsePI;
if Assigned(doc) then
doc.AppendChild(CreatePINode);
end end
else else
begin begin
@ -2617,48 +2763,22 @@ begin
FatalError('Illegal character in DTD'); FatalError('Illegal character in DTD');
end; end;
procedure TXMLTextReader.ProcessDTD(ASource: TXMLCharSource); procedure TLoader.ProcessDTD(ADoc: TDOMDocument; AReader: TXMLTextReader);
begin begin
doc := TXMLDocument.Create; AReader.FDocType := TDTDModel.Create(AReader.FNameTable);
FNameTable := doc.Names;
FDocType := TDTDModel.Create(FNameTable);
// 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(TDOMDocumentType.Create(doc, FDocType)); doc.AppendChild(TDOMDocumentType.Create(doc, AReader.FDocType));
NSPrepare; AReader.FSource.Initialize;
Initialize(ASource); AReader.ParseMarkupDecl;
ParseMarkupDecl;
end; end;
procedure TXMLTextReader.LoadEntity(AEntity: TEntityDecl); procedure TXMLTextReader.LoadEntity(AEntity: TEntityDecl);
var var
InnerReader: TXMLTextReader; ldr: TLoader;
Src: TXMLCharSource;
Ent: TDOMEntityEx;
DoctypeNode: TDOMDocumentType;
begin begin
if Assigned(doc) then if Assigned(FDoc) then
DoctypeNode := doc.DocType ldr.ProcessEntity(FDoc, Self, AEntity);
else
Exit;
if DoctypeNode = nil then
Exit;
Ent := TDOMEntityEx(DocTypeNode.Entities.GetNamedItem(AEntity.FName));
if Ent = nil then
Exit;
InnerReader := TXMLTextReader.Create(FCtrl);
try
InnerReader.FDocType := FDocType.Reference;
EntityToSource(AEntity, Src);
Ent.SetReadOnly(False);
if Assigned(Src) then
InnerReader.ProcessFragment(Src, Ent);
AEntity.FResolved := True;
finally
InnerReader.Free;
AEntity.FOnStack := False;
Ent.SetReadOnly(True);
end;
end; end;
@ -2750,8 +2870,7 @@ end;
function TXMLTextReader.GetBaseUri: XMLString; function TXMLTextReader.GetBaseUri: XMLString;
begin begin
{ TODO: implement } result := FSource.SystemID;
result := '';
end; end;
function TXMLTextReader.MoveToFirstAttribute: Boolean; function TXMLTextReader.MoveToFirstAttribute: Boolean;
@ -3133,26 +3252,6 @@ begin
FNext := xtText; FNext := xtText;
end; end;
function TXMLTextReader.DoStartElement: TDOMElement;
var
Attr: TDOMAttr;
i: Integer;
begin
with FCurrNode^.FQName^ do
Result := doc.CreateElementBuf(PWideChar(Key), Length(Key));
if Assigned(FCurrNode^.FNsUri) then
Result.SetNSI(FCurrNode^.FNsUri^.Key, FCurrNode^.FColonPos+1);
for i := 1 to FAttrCount do
begin
Attr := LoadAttribute(doc, @FNodeStack[FNesting+i]);
Result.SetAttributeNode(Attr);
// Attach element to ID map entry if necessary
if Assigned(FNodeStack[FNesting+i].FIDEntry) then
FNodeStack[FNesting+i].FIDEntry^.Data := Result;
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
@ -3206,53 +3305,6 @@ const
ntText ntText
); );
procedure TXMLTextReader.ParseContent(cursor: TDOMNode_WithChildren);
var
element: TDOMElement;
begin
while Read do
begin
if FValidate then
ValidateCurrentNode;
case FCurrNode^.FNodeType of
ntText:
cursor.InternalAppend(doc.CreateTextNodeBuf(FValue.Buffer, FValue.Length, False));
ntWhitespace, ntSignificantWhitespace:
if FPreserveWhitespace then
cursor.InternalAppend(doc.CreateTextNodeBuf(FValue.Buffer, FValue.Length, FCurrNode^.FNodeType = ntWhitespace));
ntCDATA:
cursor.InternalAppend(DoCDSect(FValue.Buffer, FValue.Length));
ntProcessingInstruction:
cursor.InternalAppend(CreatePINode);
ntComment:
if not FIgnoreComments then
cursor.InternalAppend(doc.CreateCommentBuf(FCurrNode^.FValueStart, FCurrNode^.FValueLength));
ntElement:
begin
element := DoStartElement;
cursor.InternalAppend(element);
cursor := element;
end;
ntEndElement:
cursor := TDOMNode_WithChildren(cursor.ParentNode);
ntDocumentType:
if not FCanonical then
cursor.InternalAppend(TDOMDocumentType.Create(doc, FDocType));
ntEntityReference:
cursor.InternalAppend(doc.CreateEntityReference(FCurrNode^.FQName^.Key));
end;
end;
end;
function TXMLTextReader.ReadTopLevel: Boolean; function TXMLTextReader.ReadTopLevel: Boolean;
var var
nonWs: Boolean; nonWs: Boolean;
@ -3366,7 +3418,12 @@ begin
Result := False; Result := False;
Exit; Exit;
end; end;
FReadState := rsInteractive; if FReadState = rsInitial then
begin
FReadState := rsInteractive;
FSource.Initialize;
FNext := xtText;
end;
if FAttrReadState <> arsNone then if FAttrReadState <> arsNone then
CleanAttrReadState; CleanAttrReadState;
if FNext = xtPopEmptyElement then if FNext = xtPopEmptyElement then
@ -3973,17 +4030,6 @@ begin
DoErrorPos(esError, 'Notation ''%s'' is not declared', [Value], Loc); DoErrorPos(esError, 'Notation ''%s'' is not declared', [Value], Loc);
end; end;
function TXMLTextReader.DoCDSect(ch: PWideChar; Count: Integer): TDOMNode;
var
s: XMLString;
begin
Assert(not FCDSectionsAsText, 'Should not be called when CDSectionsAsText=True');
SetString(s, ch, Count);
result := doc.CreateCDATASection(s);
end;
procedure TXMLTextReader.DoNotationDecl(const aName, aPubID, aSysID: XMLString); procedure TXMLTextReader.DoNotationDecl(const aName, aPubID, aSysID: XMLString);
var var
Notation: TNotationDecl; Notation: TNotationDecl;
@ -4190,14 +4236,14 @@ procedure ReadXMLFile(out ADoc: TXMLDocument; var f: Text);
var var
Reader: TXMLTextReader; Reader: TXMLTextReader;
Src: TXMLCharSource; Src: TXMLCharSource;
ldr: TLoader;
begin begin
ADoc := nil; ADoc := TXMLDocument.Create;
Src := TXMLFileInputSource.Create(f); Src := TXMLFileInputSource.Create(f);
Reader := TXMLTextReader.Create; Reader := TXMLTextReader.Create(Src, ADoc.Names);
try try
Reader.ProcessXML(Src); ldr.ProcessXML(ADoc,Reader);
finally finally
ADoc := TXMLDocument(Reader.Doc);
Reader.Free; Reader.Free;
end; end;
end; end;
@ -4206,15 +4252,15 @@ procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream; const ABaseURI: String
var var
Reader: TXMLTextReader; Reader: TXMLTextReader;
Src: TXMLCharSource; Src: TXMLCharSource;
ldr: TLoader;
begin begin
ADoc := nil; ADoc := TXMLDocument.Create;
Reader := TXMLTextReader.Create; Src := TXMLStreamInputSource.Create(f, False);
Src.SystemID := ABaseURI;
Reader := TXMLTextReader.Create(Src, ADoc.Names);
try try
Src := TXMLStreamInputSource.Create(f, False); ldr.ProcessXML(ADoc, Reader);
Src.SystemID := ABaseURI;
Reader.ProcessXML(Src);
finally finally
ADoc := TXMLDocument(Reader.doc);
Reader.Free; Reader.Free;
end; end;
end; end;
@ -4241,11 +4287,12 @@ procedure ReadXMLFragment(AParentNode: TDOMNode; var f: Text);
var var
Reader: TXMLTextReader; Reader: TXMLTextReader;
Src: TXMLCharSource; Src: TXMLCharSource;
ldr: TLoader;
begin begin
Reader := TXMLTextReader.Create; Src := TXMLFileInputSource.Create(f);
Reader := TXMLTextReader.Create(Src, AParentNode.OwnerDocument.Names);
try try
Src := TXMLFileInputSource.Create(f); ldr.ProcessFragment(AParentNode, Reader);
Reader.ProcessFragment(Src, AParentNode);
finally finally
Reader.Free; Reader.Free;
end; end;
@ -4255,12 +4302,13 @@ procedure ReadXMLFragment(AParentNode: TDOMNode; f: TStream; const ABaseURI: Str
var var
Reader: TXMLTextReader; Reader: TXMLTextReader;
Src: TXMLCharSource; Src: TXMLCharSource;
ldr: TLoader;
begin begin
Reader := TXMLTextReader.Create; Src := TXMLStreamInputSource.Create(f, False);
Src.SystemID := ABaseURI;
Reader := TXMLTextReader.Create(Src, AParentNode.OwnerDocument.Names);
try try
Src := TXMLStreamInputSource.Create(f, False); ldr.ProcessFragment(AParentNode, Reader);
Src.SystemID := ABaseURI;
Reader.ProcessFragment(Src, AParentNode);
finally finally
Reader.Free; Reader.Free;
end; end;
@ -4288,14 +4336,14 @@ procedure ReadDTDFile(out ADoc: TXMLDocument; var f: Text);
var var
Reader: TXMLTextReader; Reader: TXMLTextReader;
Src: TXMLCharSource; Src: TXMLCharSource;
ldr: TLoader;
begin begin
ADoc := nil; ADoc := TXMLDocument.Create;
Reader := TXMLTextReader.Create; Src := TXMLFileInputSource.Create(f);
Reader := TXMLTextReader.Create(Src, ADoc.Names);
try try
Src := TXMLFileInputSource.Create(f); ldr.ProcessDTD(ADoc,Reader);
Reader.ProcessDTD(Src);
finally finally
ADoc := TXMLDocument(Reader.doc);
Reader.Free; Reader.Free;
end; end;
end; end;
@ -4304,15 +4352,15 @@ procedure ReadDTDFile(out ADoc: TXMLDocument; f: TStream; const ABaseURI: String
var var
Reader: TXMLTextReader; Reader: TXMLTextReader;
Src: TXMLCharSource; Src: TXMLCharSource;
ldr: TLoader;
begin begin
ADoc := nil; ADoc := TXMLDocument.Create;
Reader := TXMLTextReader.Create; Src := TXMLStreamInputSource.Create(f, False);
Src.SystemID := ABaseURI;
Reader := TXMLTextReader.Create(Src, ADoc.Names);
try try
Src := TXMLStreamInputSource.Create(f, False); ldr.ProcessDTD(ADoc,Reader);
Src.SystemID := ABaseURI;
Reader.ProcessDTD(Src);
finally finally
ADoc := TXMLDocument(Reader.doc);
Reader.Free; Reader.Free;
end; end;
end; end;