فهرست منبع

* 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 -
sergei 13 سال پیش
والد
کامیت
a417e9d0b6
1فایلهای تغییر یافته به همراه279 افزوده شده و 231 حذف شده
  1. 279 231
      packages/fcl-xml/src/xmlread.pp

+ 279 - 231
packages/fcl-xml/src/xmlread.pp

@@ -276,6 +276,7 @@ type
     FNameTable: THashTable;
     FCtrl: TDOMParser;
     FXML11: Boolean;
+    FNameTableOwned: Boolean;
     FState: TXMLReadState;
     FHavePERefs: Boolean;
     FInsideDecl: Boolean;
@@ -321,7 +322,6 @@ type
     procedure SetEOFState;
     procedure SkipQuote(out Delim: WideChar; required: Boolean = True);
     procedure Initialize(ASource: TXMLCharSource);
-    procedure NSPrepare;
     procedure EntityToSource(AEntity: TEntityDecl; out Src: TXMLCharSource);
     function ContextPush(AEntity: TEntityDecl): Boolean;
     function ContextPop(Forced: Boolean = False): Boolean;
@@ -383,7 +383,6 @@ type
     procedure ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean);   // [10]
     procedure ParseComment(discard: Boolean);                           // [15]
     procedure ParsePI;                                                  // [16]
-    function CreatePINode: TDOMNode;
     procedure ParseXmlOrTextDecl(TextDecl: Boolean);
     procedure ExpectEq;
     procedure ParseDoctypeDecl;                                         // [28]
@@ -391,12 +390,10 @@ type
     procedure ParseIgnoreSection;
     procedure ParseStartTag;                                            // [39]
     procedure ParseEndTag;                                              // [42]
-    function DoStartElement: TDOMElement;
     procedure HandleEntityStart;
     procedure HandleEntityEnd;
     procedure DoStartEntity;
     procedure ParseAttribute(ElDef: TElementDecl);
-    procedure ParseContent(cursor: TDOMNode_WithChildren);              // [43]
     function  ReadTopLevel: Boolean;
     procedure NextAttrValueChunk;
   public
@@ -452,16 +449,32 @@ type
     procedure ValidationErrorWithName(const Msg: string; LineOffs: Integer = -1);
     procedure DTDReloadHook;
     procedure ConvertSource(SrcIn: TXMLInputSource; out SrcOut: TXMLCharSource);
-    function DoCDSect(ch: PWideChar; Count: Integer): TDOMNode;
     procedure DoNotationDecl(const aName, aPubID, aSysID: XMLString);
+    procedure SetOptions(AParser: TDOMParser);
   public
-    doc: TDOMDocument;
+    { Entity loading still needs to reference the document, at least as an opaque pointer }
+    FDoc: TObject;
     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;
-    procedure ProcessXML(ASource: TXMLCharSource);                // [1]
-    procedure ProcessFragment(ASource: TXMLCharSource; AOwner: TDOMNode);
-    procedure ProcessDTD(ASource: TXMLCharSource);               // ([29])
+    procedure AfterConstruction; override;
+  end;
+
+  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;
 
 const
@@ -564,41 +577,39 @@ end;
 
 procedure TDOMParser.Parse(Src: TXMLInputSource; out ADoc: TXMLDocument);
 var
-  InputSrc: TXMLCharSource;
+  Reader: TXMLTextReader;
+  ldr: TLoader;
 begin
-  with TXMLTextReader.Create(Self) do
+  ADoc := TXMLDocument.Create;
+  Reader := TXMLTextReader.Create(Src, ADoc.Names, Self);
   try
-    ConvertSource(Src, InputSrc);  // handles 'no-input-specified' case
-    ProcessXML(InputSrc)
+    ldr.ProcessXML(ADoc, Reader);
   finally
-    ADoc := TXMLDocument(doc);
-    Free;
+    Reader.Free;
   end;
 end;
 
 procedure TDOMParser.ParseUri(const URI: XMLString; out ADoc: TXMLDocument);
 var
-  Src: TXMLCharSource;
+  Reader: TXMLTextReader;
+  ldr: TLoader;
 begin
-  ADoc := nil;
-  with TXMLTextReader.Create(Self) do
+  ADoc := TXMLDocument.Create;
+  Reader := TXMLTextReader.Create(URI, ADoc.Names, Self);
   try
-    if ResolveResource(URI, '', '', Src) then
-      ProcessXML(Src)
-    else
-      DoErrorPos(esFatal, 'The specified URI could not be resolved', NullLocation);
+    ldr.ProcessXML(ADoc, Reader)
   finally
-    ADoc := TXMLDocument(doc);
-    Free;
+    Reader.Free;
   end;
 end;
 
 function TDOMParser.ParseWithContext(Src: TXMLInputSource;
   Context: TDOMNode; Action: TXMLContextAction): TDOMNode;
 var
-  InputSrc: TXMLCharSource;
   Frag: TDOMDocumentFragment;
   node: TDOMNode;
+  reader: TXMLTextReader;
+  ldr: TLoader;
 begin
   if Action in [xaInsertBefore, xaInsertAfter, xaReplace] then
     node := Context.ParentNode
@@ -611,12 +622,11 @@ begin
   if not (node.NodeType in [ELEMENT_NODE, DOCUMENT_FRAGMENT_NODE]) then
     raise EDOMHierarchyRequest.Create('DOMParser.ParseWithContext');
 
-  with TXMLTextReader.Create(Self) do
+  reader := TXMLTextReader.Create(Src, Context.OwnerDocument.Names, Self);
   try
-    ConvertSource(Src, InputSrc);    // handles 'no-input-specified' case
     Frag := Context.OwnerDocument.CreateDocumentFragment;
     try
-      ProcessFragment(InputSrc, Frag);
+      ldr.ProcessFragment(Frag, reader);
       Result := Frag.FirstChild;
       case Action of
         xaAppendAsChildren: Context.AppendChild(Frag);
@@ -633,7 +643,7 @@ begin
       Frag.Free;
     end;
   finally
-    Free;
+    reader.Free;
   end;
 end;
 
@@ -1275,9 +1285,8 @@ begin
   SetLength(FValidators, 16);
 end;
 
-constructor TXMLTextReader.Create(AParser: TDOMParser);
+procedure TXMLTextReader.SetOptions(AParser: TDOMParser);
 begin
-  Create;
   FCtrl := AParser;
   if FCtrl = nil then
     Exit;
@@ -1293,6 +1302,51 @@ begin
   FMaxChars := FCtrl.Options.MaxChars;
 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;
 var
   i: Integer;
@@ -1314,16 +1368,17 @@ begin
   FIDMap.Free;
   FForwardRefs.Free;
   FAttrChunks.Free;
-  if doc = nil then
+  if FNameTableOwned then
     FNameTable.Free;
   inherited Destroy;
 end;
 
 
-{ Must be executed after doc has been set.
-  After introducing own NameTable, merge this into constructor }
-procedure TXMLTextReader.NSPrepare;
+procedure TXMLTextReader.AfterConstruction;
 begin
+  FNesting := 0;
+  FValidatorNesting := 0;
+  FCurrNode := @FNodeStack[0];
   if FNamespaces then
   begin
     FNSHelper := TNSSupport.Create;
@@ -1336,63 +1391,165 @@ begin
   end;
 end;
 
-procedure TXMLTextReader.ProcessXML(ASource: TXMLCharSource);
+procedure TLoader.ProcessXML(ADoc: TDOMDocument; AReader: TXMLTextReader);
 begin
-  doc := TXMLDocument.Create;
-  doc.documentURI := ASource.SystemID;  // TODO: to be changed to URI or BaseURI
-  FNameTable := doc.Names;
-  FState := rsProlog;
-  FNesting := 0;
-  FValidatorNesting := 0;
-  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;
+  doc := ADoc;
+  reader := AReader;
+  reader.FDoc := ADoc;
+  doc.documentURI := reader.BaseURI;
+  reader.FState := rsProlog;
+  reader.FFragmentMode := False;
   ParseContent(doc);
+  doc.XMLStandalone := reader.FStandalone;
 
-  if FValidate then
-    ValidateIdRefs;
+  if reader.FValidate then
+    reader.ValidateIdRefs;
 
-  doc.IDs := FIDMap;
-  FIDMap := nil;
+  doc.IDs := reader.FIDMap;
+  reader.FIDMap := nil;
 end;
 
-procedure TXMLTextReader.ProcessFragment(ASource: TXMLCharSource; AOwner: TDOMNode);
+procedure TLoader.ProcessFragment(AOwner: TDOMNode; AReader: TXMLTextReader);
 var
   DoctypeNode: TDOMDocumentTypeEx;
 begin
   doc := AOwner.OwnerDocument;
-  FNameTable := doc.Names;
-  FState := rsRoot;
-  FNesting := 0;
-  FValidatorNesting := 0;
-  FCurrNode := @FNodeStack[0];
-  FFragmentMode := True;
-  FXML11 := doc.XMLVersion = '1.1';
-  NSPrepare;
-  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
+  reader := AReader;
+  reader.FDoc := doc;
+  reader.FState := rsRoot;
+  reader.FFragmentMode := True;
+  reader.FXML11 := doc.XMLVersion = '1.1';
+  DoctypeNode := TDOMDocumentTypeEx(doc.DocType);
+  if Assigned(DoctypeNode) then
+    reader.FDocType := DocTypeNode.FModel.Reference;
+  ParseContent(aOwner as TDOMNode_WithChildren);
+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
-    DoctypeNode := TDOMDocumentTypeEx(doc.DocType);
-    if Assigned(DoctypeNode) then
-      FDocType := DocTypeNode.FModel.Reference;
+    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;
-  if AOwner is TDOMEntity then
+
+  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
-    TDOMTopNodeEx(AOwner).FXMLVersion := FSource.FXMLVersion;
-    TDOMTopNodeEx(AOwner).FXMLEncoding := FSource.FXMLEncoding;
+    Result := doc.CreateElementBuf(PWideChar(FQName^.Key), Length(FQName^.Key));
+    if Assigned(FNsUri) then
+      Result.SetNSI(FNsUri^.Key, FColonPos+1);
   end;
-  FNext := xtText;
-  ParseContent(aOwner as TDOMNode_WithChildren);
+
+  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;
 var
   p: PWideChar;
@@ -1922,15 +2079,6 @@ begin
     FNameTable.FindOrAdd(FName.Buffer, FName.Length));
 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
   vers: array[Boolean] of TXMLVersion = (xmlVersion10, xmlVersion11);
 
@@ -2550,8 +2698,6 @@ begin
     if FSource.FBuf^ = '?' then
     begin
       ParsePI;
-      if Assigned(doc) then
-        doc.AppendChild(CreatePINode);
     end
     else
     begin
@@ -2617,48 +2763,22 @@ begin
     FatalError('Illegal character in DTD');
 end;
 
-procedure TXMLTextReader.ProcessDTD(ASource: TXMLCharSource);
+procedure TLoader.ProcessDTD(ADoc: TDOMDocument; AReader: TXMLTextReader);
 begin
-  doc := TXMLDocument.Create;
-  FNameTable := doc.Names;
-  FDocType := TDTDModel.Create(FNameTable);
+  AReader.FDocType := TDTDModel.Create(AReader.FNameTable);
   // TODO: DTD labeled version 1.1 will be rejected - must set FXML11 flag
-  doc.AppendChild(TDOMDocumentType.Create(doc, FDocType));
-  NSPrepare;
-  Initialize(ASource);
-  ParseMarkupDecl;
+  doc.AppendChild(TDOMDocumentType.Create(doc, AReader.FDocType));
+  AReader.FSource.Initialize;
+  AReader.ParseMarkupDecl;
 end;
 
 
 procedure TXMLTextReader.LoadEntity(AEntity: TEntityDecl);
 var
-  InnerReader: TXMLTextReader;
-  Src: TXMLCharSource;
-  Ent: TDOMEntityEx;
-  DoctypeNode: TDOMDocumentType;
+  ldr: TLoader;
 begin
-  if Assigned(doc) then
-    DoctypeNode := doc.DocType
-  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;
+  if Assigned(FDoc) then
+    ldr.ProcessEntity(FDoc, Self, AEntity);
 end;
 
 
@@ -2750,8 +2870,7 @@ end;
 
 function TXMLTextReader.GetBaseUri: XMLString;
 begin
-  { TODO: implement }
-  result := '';
+  result := FSource.SystemID;
 end;
 
 function TXMLTextReader.MoveToFirstAttribute: Boolean;
@@ -3133,26 +3252,6 @@ begin
   FNext := xtText;
 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.
 // To minimize CPU cache effects, methods from different classes are kept together
 
@@ -3206,53 +3305,6 @@ const
     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;
 var
   nonWs: Boolean;
@@ -3366,7 +3418,12 @@ begin
     Result := False;
     Exit;
   end;
-  FReadState := rsInteractive;
+  if FReadState = rsInitial then
+  begin
+    FReadState := rsInteractive;
+    FSource.Initialize;
+    FNext := xtText;
+  end;
   if FAttrReadState <> arsNone then
     CleanAttrReadState;
   if FNext = xtPopEmptyElement then
@@ -3973,17 +4030,6 @@ begin
         DoErrorPos(esError, 'Notation ''%s'' is not declared', [Value], Loc);
 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);
 var
   Notation: TNotationDecl;
@@ -4190,14 +4236,14 @@ procedure ReadXMLFile(out ADoc: TXMLDocument; var f: Text);
 var
   Reader: TXMLTextReader;
   Src: TXMLCharSource;
+  ldr: TLoader;
 begin
-  ADoc := nil;
+  ADoc := TXMLDocument.Create;
   Src := TXMLFileInputSource.Create(f);
-  Reader := TXMLTextReader.Create;
+  Reader := TXMLTextReader.Create(Src, ADoc.Names);
   try
-    Reader.ProcessXML(Src);
+    ldr.ProcessXML(ADoc,Reader);
   finally
-    ADoc := TXMLDocument(Reader.Doc);
     Reader.Free;
   end;
 end;
@@ -4206,15 +4252,15 @@ procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream; const ABaseURI: String
 var
   Reader: TXMLTextReader;
   Src: TXMLCharSource;
+  ldr: TLoader;
 begin
-  ADoc := nil;
-  Reader := TXMLTextReader.Create;
+  ADoc := TXMLDocument.Create;
+  Src := TXMLStreamInputSource.Create(f, False);
+  Src.SystemID := ABaseURI;
+  Reader := TXMLTextReader.Create(Src, ADoc.Names);
   try
-    Src := TXMLStreamInputSource.Create(f, False);
-    Src.SystemID := ABaseURI;
-    Reader.ProcessXML(Src);
+    ldr.ProcessXML(ADoc, Reader);
   finally
-    ADoc := TXMLDocument(Reader.doc);
     Reader.Free;
   end;
 end;
@@ -4241,11 +4287,12 @@ procedure ReadXMLFragment(AParentNode: TDOMNode; var f: Text);
 var
   Reader: TXMLTextReader;
   Src: TXMLCharSource;
+  ldr: TLoader;
 begin
-  Reader := TXMLTextReader.Create;
+  Src := TXMLFileInputSource.Create(f);
+  Reader := TXMLTextReader.Create(Src, AParentNode.OwnerDocument.Names);
   try
-    Src := TXMLFileInputSource.Create(f);
-    Reader.ProcessFragment(Src, AParentNode);
+    ldr.ProcessFragment(AParentNode, Reader);
   finally
     Reader.Free;
   end;
@@ -4255,12 +4302,13 @@ procedure ReadXMLFragment(AParentNode: TDOMNode; f: TStream; const ABaseURI: Str
 var
   Reader: TXMLTextReader;
   Src: TXMLCharSource;
+  ldr: TLoader;
 begin
-  Reader := TXMLTextReader.Create;
+  Src := TXMLStreamInputSource.Create(f, False);
+  Src.SystemID := ABaseURI;
+  Reader := TXMLTextReader.Create(Src, AParentNode.OwnerDocument.Names);
   try
-    Src := TXMLStreamInputSource.Create(f, False);
-    Src.SystemID := ABaseURI;
-    Reader.ProcessFragment(Src, AParentNode);
+    ldr.ProcessFragment(AParentNode, Reader);
   finally
     Reader.Free;
   end;
@@ -4288,14 +4336,14 @@ procedure ReadDTDFile(out ADoc: TXMLDocument; var f: Text);
 var
   Reader: TXMLTextReader;
   Src: TXMLCharSource;
+  ldr: TLoader;
 begin
-  ADoc := nil;
-  Reader := TXMLTextReader.Create;
+  ADoc := TXMLDocument.Create;
+  Src := TXMLFileInputSource.Create(f);
+  Reader := TXMLTextReader.Create(Src, ADoc.Names);
   try
-    Src := TXMLFileInputSource.Create(f);
-    Reader.ProcessDTD(Src);
+    ldr.ProcessDTD(ADoc,Reader);
   finally
-    ADoc := TXMLDocument(Reader.doc);
     Reader.Free;
   end;
 end;
@@ -4304,15 +4352,15 @@ procedure ReadDTDFile(out ADoc: TXMLDocument; f: TStream; const ABaseURI: String
 var
   Reader: TXMLTextReader;
   Src: TXMLCharSource;
+  ldr: TLoader;
 begin
-  ADoc := nil;
-  Reader := TXMLTextReader.Create;
+  ADoc := TXMLDocument.Create;
+  Src := TXMLStreamInputSource.Create(f, False);
+  Src.SystemID := ABaseURI;
+  Reader := TXMLTextReader.Create(Src, ADoc.Names);
   try
-    Src := TXMLStreamInputSource.Create(f, False);
-    Src.SystemID := ABaseURI;
-    Reader.ProcessDTD(Src);
+    ldr.ProcessDTD(ADoc,Reader);
   finally
-    ADoc := TXMLDocument(Reader.doc);
     Reader.Free;
   end;
 end;