LibXmlParser.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:101k
源码类别:

2D图形编程

开发平台:

Delphi

  1. (**
  2. ===============================================================================================
  3. Name    : LibXmlParser
  4. ===============================================================================================
  5. Project : All Projects
  6. ===============================================================================================
  7. Subject : Progressive XML Parser for all types of XML Files
  8. ===============================================================================================
  9. Author  : Stefan Heymann
  10.           Eschenweg 3
  11.           72076 T黚ingen
  12.           GERMANY
  13. E-Mail:   stefan@destructor.de
  14. URL:      www.destructor.de
  15. ===============================================================================================
  16. Source, Legals ("Licence")
  17. --------------------------
  18. The official site to get this parser is http://www.destructor.de/
  19. Usage and Distribution of this Source Code is ruled by the
  20. "Destructor.de Source code Licence" (DSL) which comes with this file or
  21. can be downloaded at http://www.destructor.de/
  22. IN SHORT: Usage and distribution of this source code is free.
  23.           You use it completely on your own risk.
  24. Postcardware
  25. ------------
  26. If you like this code, please send a postcard of your city to my above address.
  27. ===============================================================================================
  28. !!!  All parts of this code which are not finished or not conforming exactly to
  29.      the XmlSpec are marked with three exclamation marks
  30. -!-  Parts where the parser may be able to detect errors in the document's syntax are
  31.      marked with the dash-exlamation mark-dash sequence.
  32. ===============================================================================================
  33. Terminology:
  34. ------------
  35. - Start:   Start of a buffer part
  36. - Final:   End (last character) of a buffer part
  37. - DTD:     Document Type Definition
  38. - DTDc:    Document Type Declaration
  39. - XMLSpec: The current W3C XML Recommendation (version 1.0 as of 1998-02-10), Chapter No.
  40. - Cur*:    Fields concerning the "Current" part passed back by the "Scan" method
  41. ===============================================================================================
  42. Scanning the XML document
  43. -------------------------
  44. - Create TXmlParser Instance                     MyXml := TXmlParser.Create;
  45. - Load XML Document                              MyXml.LoadFromFile (Filename);
  46. - Start Scanning                                 MyXml.StartScan;
  47. - Scan Loop                                      WHILE MyXml.Scan DO
  48. - Test for Part Type                               CASE MyXml.CurPartType OF
  49. - Handle Parts                                       ... : ;;;
  50. - Handle Parts                                       ... : ;;;
  51. - Handle Parts                                       ... : ;;;
  52.                                                      END;
  53. - Destroy                                        MyXml.Free;
  54. ===============================================================================================
  55. Loading the XML document
  56. ------------------------
  57. You can load the XML document from a file with the "LoadFromFile" method.
  58. It is beyond the scope of this parser to perform HTTP or FTP accesses. If you want your
  59. application to handle such requests (URLs), you can load the XML via HTTP or FTP or whatever
  60. protocol and hand over the data buffer using the "LoadFromBuffer" or "SetBuffer" method.
  61. "LoadFromBuffer" loads the internal buffer of TXmlParser with the given null-terminated
  62. string, thereby creating a copy of that buffer.
  63. "SetBuffer" just takes the pointer to another buffer, which means that the given
  64. buffer pointer must be valid while the document is accessed via TXmlParser.
  65. ===============================================================================================
  66. Encodings:
  67. ----------
  68. This XML parser kind of "understands" the following encodings:
  69. - UTF-8
  70. - ISO-8859-1
  71. - Windows-1252
  72. Any flavor of multi-byte characters (and this includes UTF-16) is not supported. Sorry.
  73. Every string which has to be passed to the application passes the virtual method
  74. "TranslateEncoding" which translates the string from the current encoding (stored in
  75. "CurEncoding") into the encoding the application wishes to receive.
  76. The "TranslateEncoding" method that is built into TXmlParser assumes that the application
  77. wants to receive Windows ANSI (Windows-1252, about the same as ISO-8859-1) and is able
  78. to convert UTF-8 and ISO-8859-1 encodings.
  79. For other source and target encodings, you will have to override "TranslateEncoding".
  80. ===============================================================================================
  81. Buffer Handling
  82. ---------------
  83. - The document must be loaded completely into a piece of RAM
  84. - All character positions are referenced by PChar pointers
  85. - The TXmlParser instance can either "own" the buffer itself (then, FBufferSize is > 0)
  86.   or reference the buffer of another instance or object (then, FBuffersize is 0 and
  87.   FBuffer is not NIL)
  88. - The Property DocBuffer passes back a pointer to the first byte of the document. If there
  89.   is no document stored (FBuffer is NIL), the DocBuffer returns a pointer to a NULL character.
  90. ===============================================================================================
  91. Whitespace Handling
  92. -------------------
  93. The TXmlParser property "PackSpaces" determines how Whitespace is returned in Text Content:
  94. While PackSpaces is true, all leading and trailing whitespace characters are trimmed of, all
  95. Whitespace is converted to Space #x20 characters and contiguous Whitespace characters are
  96. compressed to one.
  97. If the "Scan" method reports a ptContent part, the application can get the original text
  98. with all whitespace characters by extracting the characters from "CurStart" to "CurFinal".
  99. If the application detects an xml:space attribute, it can set "PackSpaces" accordingly or
  100. use CurStart/CurFinal.
  101. Please note that TXmlParser does _not_ normalize Line Breaks to single LineFeed characters
  102. as the XmlSpec requires (XmlSpec 2.11).
  103. The xml:space attribute is not handled by TXmlParser. This is on behalf of the application.
  104. ===============================================================================================
  105. Non-XML-Conforming
  106. ------------------
  107. TXmlParser does not conform 100 % exactly to the XmlSpec:
  108. - UTF-16 is not supported (XmlSpec 2.2)
  109.   (Workaround: Convert UTF-16 to UTF-8 and hand the buffer over to TXmlParser)
  110. - As the parser only works with single byte strings, all Unicode characters > 255
  111.   can currently not be handled correctly.
  112. - Line breaks are not normalized to single Linefeed #x0A characters (XmlSpec 2.11)
  113.   (Workaround: The Application can access the text contents on its own [CurStart, CurFinal],
  114.   thereby applying every normalization it wishes to)
  115. - The attribute value normalization does not work exactly as defined in the
  116.   Second Edition of the XML 1.0 specification.
  117. - See also the code parts marked with three consecutive exclamation marks. These are
  118.   parts which are not finished in the current code release.
  119. This list may be incomplete, so it may grow if I get to know any other points.
  120. As work on the parser proceeds, this list may also shrink.
  121. ===============================================================================================
  122. Things Todo
  123. -----------
  124. - Introduce a new event/callback which is called when there is an unresolvable
  125.   entity or character reference
  126. - Support Unicode
  127. - Use Streams instead of reading the whole XML into memory
  128. ===============================================================================================
  129. Change History, Version numbers
  130. -------------------------------
  131. The Date is given in ISO Year-Month-Day (YYYY-MM-DD) order.
  132. Versions are counted from 1.0.0 beginning with the version from 2000-03-16.
  133. Unreleased versions don't get a version number.
  134. Date        Author Version Changes
  135. -----------------------------------------------------------------------------------------------
  136. 2000-03-16  HeySt  1.0.0   Start
  137. 2000-03-28  HeySt  1.0.1   Initial Publishing of TXmlParser on the destructor.de Web Site
  138. 2000-03-30  HeySt  1.0.2   TXmlParser.AnalyzeCData: Call "TranslateEncoding" for CurContent
  139. 2000-03-31  HeySt  1.0.3   Deleted the StrPosE function (was not needed anyway)
  140. 2000-04-04  HeySt  1.0.4   TDtdElementRec modified: Start/Final for all Elements;
  141.                            Should be backwards compatible.
  142.                            AnalyzeDtdc: Set CurPartType to ptDtdc
  143. 2000-04-23  HeySt  1.0.5   New class TObjectList. Eliminated reference to the Delphi 5
  144.                            "Contnrs" unit so LibXmlParser is Delphi 4 compatible.
  145. 2000-07-03  HeySt  1.0.6   TNvpNode: Added Constructor
  146. 2000-07-11  HeySt  1.0.7   Removed "Windows" from USES clause
  147.                            Added three-exclamation-mark comments for Utf8ToAnsi/AnsiToUtf8
  148.                            Added three-exclamation-mark comments for CHR function calls
  149. 2000-07-23  HeySt  1.0.8   TXmlParser.Clear: CurAttr.Clear; EntityStack.Clear;
  150.                            (This was not a bug; just defensive programming)
  151. 2000-07-29  HeySt  1.0.9   TNvpList: Added methods: Node(Index), Value(Index), Name(Index);
  152. 2000-10-07  HeySt          Introduced Conditional Defines
  153.                            Uses Contnrs unit and its TObjectList class again for
  154.                            Delphi 5 and newer versions
  155. 2001-01-30  HeySt          Introduced Version Numbering
  156.                            Made LoadFromFile and LoadFromBuffer BOOLEAN functions
  157.                            Introduced FileMode parameter for LoadFromFile
  158.                            BugFix: TAttrList.Analyze: Must add CWhitespace to ExtractName call
  159.                            Comments worked over
  160. 2001-02-28  HeySt  1.0.10  Completely worked over and tested the UTF-8 functions
  161.                            Fixed a bug in TXmlParser.Scan which caused it to start over when it
  162.                            was called after the end of scanning, resulting in an endless loop
  163.                            TEntityStack is now a TObjectList instead of TList
  164. 2001-07-03  HeySt  1.0.11  Updated Compiler Version IFDEFs for Kylix
  165. 2001-07-11  HeySt  1.0.12  New TCustomXmlScanner component (taken over from LibXmlComps.pas)
  166. 2001-07-14  HeySt  1.0.13  Bugfix TCustomXmlScanner.FOnTranslateEncoding
  167. 2001-10-22  HeySt          Don't clear CurName anymore when the parser finds a CDATA section.
  168. 2001-12-03  HeySt  1.0.14  TObjectList.Clear: Make call to INHERITED method (fixes a memory leak)
  169. 2001-12-05  HeySt  1.0.15  TObjectList.Clear: removed call to INHERITED method
  170.                            TObjectList.Destroy: Inserted SetCapacity call.
  171.                            Reduces need for frequent re-allocation of pointer buffer
  172.                            Dedicated to my father, Theodor Heymann
  173. 2002-06-26  HeySt  1.0.16  TXmlParser.Scan: Fixed a bug with PIs whose name is beginning
  174.                            with 'xml'. Thanks to Uwe Kamm for submitting this bug.
  175.                            The CurEncoding property is now always in uppercase letters (the XML
  176.                            spec wants it to be treated case independently so when it's uppercase
  177.                            comparisons are faster)
  178. 2002-03-04  HeySt  1.0.17  Included an IFDEF for Delphi 7 (VER150) and Kylix
  179.                            There is a new symbol HAS_CONTNRS_UNIT which is used now to
  180.                            distinguish between IDEs which come with the Contnrs unit and
  181.                            those that don't.
  182. *)
  183.  // --- Delphi/Kylix Version Numbers
  184.  //     As this is no code, this does not blow up your object or executable code at all
  185.  (*$IFDEF LINUX *)
  186.  (*$DEFINE K1_OR_NEWER *)
  187.  (*$ENDIF *)
  188.  (*$IFDEF MSWINDOWS *)
  189.  (*$DEFINE D1_OR_NEWER *)
  190.  (*$IFNDEF VER80 *)
  191.  (*$DEFINE D2_OR_NEWER *)
  192.  (*$IFNDEF VER90 *)
  193.  (*$DEFINE D3_OR_NEWER *)
  194.  (*$IFNDEF VER100 *)
  195.  (*$DEFINE D4_OR_NEWER *)
  196.  (*$IFNDEF VER120 *)
  197.  (*$DEFINE D5_OR_NEWER *)
  198.  (*$IFNDEF VER130 *)
  199.  (*$IFNDEF VER140 *)
  200.  (*$IFNDEF VER150 *)
  201. {                       If the compiler gets stuck here,
  202.                        you are using a compiler version unknown to this code.
  203.                        You will probably have to change this code accordingly.
  204.                        At first, try to comment out these lines and see what will happen.}
  205.  (*$ENDIF *)
  206.  (*$ENDIF *)
  207.  (*$ENDIF *)
  208.  (*$ENDIF *)
  209.  (*$ENDIF *)
  210.  (*$ENDIF *)
  211.  (*$ENDIF *)
  212.  (*$ENDIF *)
  213.  (*$IFDEF D5_OR_NEWER *)
  214.  (*$DEFINE HAS_CONTNRS_UNIT *)
  215.  (*$ENDIF *)
  216.  (*$IFDEF K1_OR_NEWER *)
  217.  (*$DEFINE HAS_CONTNRS_UNIT *)
  218.  (*$ENDIF *)
  219. unit LibXmlParser;
  220. interface
  221. uses
  222.   SysUtils, Classes,
  223.   (*$IFDEF HAS_CONTNRS_UNIT *)// The Contnrs Unit was introduced in Delphi 5
  224.   Contnrs,
  225.   (*$ENDIF*)
  226.   Math;
  227. const
  228.   CVersion = '1.0.17';  // This variable will be updated for every release
  229.  // (I hope, I won't forget to do it everytime ...)
  230. type
  231.   TPartType = // --- Document Part Types
  232.     (ptNone,            // Nothing
  233.     ptXmlProlog,       // XML Prolog                  XmlSpec 2.8 / 4.3.1
  234.     ptComment,         // Comment                     XmlSpec 2.5
  235.     ptPI,              // Processing Instruction      XmlSpec 2.6
  236.     ptDtdc,            // Document Type Declaration   XmlSpec 2.8
  237.     ptStartTag,        // Start Tag                   XmlSpec 3.1
  238.     ptEmptyTag,        // Empty-Element Tag           XmlSpec 3.1
  239.     ptEndTag,          // End Tag                     XmlSpec 3.1
  240.     ptContent,         // Text Content between Tags
  241.     ptCData);          // CDATA Section               XmlSpec 2.7
  242.   TDtdElemType = // --- DTD Elements
  243.     (deElement,         // !ELEMENT declaration
  244.     deAttList,         // !ATTLIST declaration
  245.     deEntity,          // !ENTITY declaration
  246.     deNotation,        // !NOTATION declaration
  247.     dePI,              // PI in DTD
  248.     deComment,         // Comment in DTD
  249.     deError);          // Error found in the DTD
  250. type
  251.   TAttrList    = class;
  252.   TEntityStack = class;
  253.   TNvpList     = class;
  254.   TElemDef     = class;
  255.   TElemList    = class;
  256.   TEntityDef   = class;
  257.   TNotationDef = class;
  258.   TDtdElementRec = record
  259.     // --- This Record is returned by the DTD parser callback function
  260.     Start, Final: PChar;
  261.       // Start/End of the Element's Declaration
  262.     case ElementType: TDtdElemType of
  263.       // Type of the Element
  264.       deElement,                                      // <!ELEMENT>
  265.       deAttList: (ElemDef: TElemDef);         // <!ATTLIST>
  266.       deEntity: (EntityDef: TEntityDef);       // <!ENTITY>
  267.       deNotation: (NotationDef: TNotationDef);     // <!NOTATION>
  268.       dePI: (Target: PChar;             // <?PI ?>
  269.         Content: PChar;
  270.         AttrList: TAttrList);
  271.       deError: (Pos: PChar);            // Error
  272.     // deComment : ((No additional fields here));   // <!-- Comment -->
  273.   end;
  274.   TXmlParser = class                             // --- Internal Properties and Methods
  275.   protected
  276.     FBuffer:     PChar;           // NIL if there is no buffer available
  277.     FBufferSize: integer;
  278.     // 0 if the buffer is not owned by the Document instance
  279.     FSource:     string;
  280.     // Name of Source of document. Filename for Documents loaded with LoadFromFile
  281.     FXmlVersion: string;
  282.     // XML version from Document header. Default is '1.0'
  283.     FEncoding:   string;
  284.     // Encoding from Document header. Default is 'UTF-8'
  285.     FStandalone: boolean;
  286.     // Standalone declaration from Document header. Default is 'yes'
  287.     FRootName:   string;          // Name of the Root Element (= DTD name)
  288.     FDtdcFinal:  PChar;
  289.     // Pointer to the '>' character terminating the DTD declaration
  290.     FNormalize:   boolean;
  291.     // If true: Pack Whitespace and don't return empty contents
  292.     EntityStack:  TEntityStack;
  293.     // Entity Stack for Parameter and General Entities
  294.     FCurEncoding: string;
  295.     // Current Encoding during parsing (always uppercase)
  296.     procedure AnalyzeProlog;
  297.     // Analyze XML Prolog or Text Declaration
  298.     procedure AnalyzeComment(Start: PChar; var Final: PChar);
  299.     // Analyze Comments
  300.     procedure AnalyzePI(Start: PChar; var Final: PChar);
  301.     // Analyze Processing Instructions (PI)
  302.     procedure AnalyzeDtdc;
  303.     // Analyze Document Type Declaration
  304.     procedure AnalyzeDtdElements(Start: PChar; var Final: PChar);
  305.     // Analyze DTD declarations
  306.     procedure AnalyzeTag;
  307.     // Analyze Start/End/Empty-Element Tags
  308.     procedure AnalyzeCData;
  309.     // Analyze CDATA Sections
  310.     procedure AnalyzeText(var IsDone: boolean);
  311.     // Analyze Text Content between Tags
  312.     procedure AnalyzeElementDecl(Start: PChar; var Final: PChar);
  313.     procedure AnalyzeAttListDecl(Start: PChar; var Final: PChar);
  314.     procedure AnalyzeEntityDecl(Start: PChar; var Final: PChar);
  315.     procedure AnalyzeNotationDecl(Start: PChar; var Final: PChar);
  316.     procedure PushPE(var Start: PChar);
  317.     procedure ReplaceCharacterEntities(var Str: string);
  318.     procedure ReplaceParameterEntities(var Str: string);
  319.     procedure ReplaceGeneralEntities(var Str: string);
  320.     function GetDocBuffer: PChar;
  321.     // Returns FBuffer or a pointer to a NUL char if Buffer is empty
  322.   public                         // --- Document Properties
  323.     property XmlVersion: string Read FXmlVersion;
  324.     // XML version from the Document Prolog
  325.     property Encoding: string Read FEncoding;
  326.     // Document Encoding from Prolog
  327.     property Standalone: boolean Read FStandalone;
  328.     // Standalone Declaration from Prolog
  329.     property RootName: string Read FRootName;
  330.     // Name of the Root Element
  331.     property Normalize: boolean Read FNormalize Write FNormalize;
  332.     // True if Content is to be normalized
  333.     property Source: string Read FSource;
  334.     // Name of Document Source (Filename)
  335.     property DocBuffer: PChar Read GetDocBuffer;
  336.     // Returns document buffer
  337.   public                         // --- DTD Objects
  338.     Elements:    TElemList;
  339.     // Elements: List of TElemDef (contains Attribute Definitions)
  340.     Entities:    TNvpList;      // General Entities: List of TEntityDef
  341.     ParEntities: TNvpList;      // Parameter Entities: List of TEntityDef
  342.     Notations:   TNvpList;      // Notations: List of TNotationDef
  343.   public
  344.     constructor Create;
  345.     destructor Destroy; override;
  346.     // --- Document Handling
  347.     function LoadFromFile(Filename: string;
  348.       FileMode: integer =
  349.       fmOpenRead or fmShareDenyNone): boolean;
  350.     // Loads Document from given file
  351.     function LoadFromBuffer(Buffer: PChar): boolean;
  352.     // Loads Document from another buffer
  353.     procedure SetBuffer(Buffer: PChar);
  354.     // References another buffer
  355.     procedure Clear;
  356.     // Clear Document
  357.   public
  358.     // --- Scanning through the document
  359.     CurPartType: TPartType;                         // Current Type
  360.     CurName:     string;                            // Current Name
  361.     CurContent:  string;
  362.     // Current Normalized Content
  363.     CurStart:    PChar;
  364.     // Current First character
  365.     CurFinal:    PChar;
  366.     // Current Last character
  367.     CurAttr:     TAttrList;
  368.     // Current Attribute List
  369.     property CurEncoding: string Read FCurEncoding; // Current Encoding
  370.     procedure StartScan;
  371.     function Scan: boolean;
  372.     // --- Events / Callbacks
  373.     function LoadExternalEntity(SystemId, PublicId,
  374.       Notation: string): TXmlParser;
  375.       virtual;
  376.     function TranslateEncoding(const Source: string): string;
  377.       virtual;
  378.     procedure DtdElementFound(DtdElementRec: TDtdElementRec);
  379.       virtual;
  380.   end;
  381.   TValueType =      // --- Attribute Value Type
  382.     (vtNormal,       // Normal specified Attribute
  383.     vtImplied,      // #IMPLIED attribute value
  384.     vtFixed,        // #FIXED attribute value
  385.     vtDefault);
  386.   // Attribute value from default value in !ATTLIST declaration
  387.   TAttrDefault =     // --- Attribute Default Type
  388.     (adDefault,      // Normal default value
  389.     adRequired,      // #REQUIRED attribute
  390.     adImplied,       // #IMPLIED attribute
  391.     adFixed);        // #FIXED attribute
  392.   TAttrType = // --- Type of attribute
  393.     (atUnknown,      // Unknown type
  394.     atCData,        // Character data only
  395.     atID,           // ID
  396.     atIdRef,        // ID Reference
  397.     atIdRefs,       // Several ID References, separated by Whitespace
  398.     atEntity,       // Name of an unparsed Entity
  399.     atEntities,
  400.     // Several unparsed Entity names, separated by Whitespace
  401.     atNmToken,      // Name Token
  402.     atNmTokens,     // Several Name Tokens, separated by Whitespace
  403.     atNotation,     // A selection of Notation names (Unparsed Entity)
  404.     atEnumeration); // Enumeration
  405.   TElemType = // --- Element content type
  406.     (etEmpty,        // Element is always empty
  407.     etAny,
  408.     // Element can have any mixture of PCDATA and any elements
  409.     etChildren,     // Element must contain only elements
  410.     etMixed);       // Mixed PCDATA and elements
  411.   (*$IFDEF HAS_CONTNRS_UNIT *)
  412.   TObjectList = Contnrs.TObjectList;    // Re-Export this identifier
  413.   (*$ELSE *)
  414.   TObjectList = class(TList)
  415.     destructor Destroy; override;
  416.     procedure Delete(Index: integer);
  417.     procedure Clear; override;
  418.   end;
  419.   (*$ENDIF *)
  420.   TNvpNode = class                     // Name-Value Pair Node
  421.     Name:  string;
  422.     Value: string;
  423.     constructor Create(TheName: string = ''; TheValue: string = '');
  424.   end;
  425.   TNvpList = class(TObjectList)       // Name-Value Pair List
  426.     procedure Add(Node: TNvpNode);
  427.     function Node(Name: string): TNvpNode; overload;
  428.     function Node(Index: integer): TNvpNode; overload;
  429.     function Value(Name: string): string; overload;
  430.     function Value(Index: integer): string; overload;
  431.     function Name(Index: integer): string;
  432.   end;
  433.   TAttr = class(TNvpNode)          // Attribute of a Start-Tag or Empty-Element-Tag
  434.     ValueType: TValueType;
  435.     AttrType:  TAttrType;
  436.   end;
  437.   TAttrList = class(TNvpList)          // List of Attributes
  438.     procedure Analyze(Start: PChar; var Final: PChar);
  439.   end;
  440.   TEntityStack = class(TObjectList)
  441.     // Stack where current position is stored before parsing entities
  442.   protected
  443.     Owner: TXmlParser;
  444.   public
  445.     constructor Create(TheOwner: TXmlParser);
  446.     procedure Push(LastPos: PChar); overload;
  447.     procedure Push(Instance: TObject; LastPos: PChar); overload;
  448.     function Pop: PChar;
  449.     // Returns next char or NIL if EOF is reached. Frees Instance.
  450.   end;
  451.   TAttrDef = class(TNvpNode)
  452.     // Represents a <!ATTLIST Definition. "Value" is the default value
  453.     TypeDef:     string;           // Type definition from the DTD
  454.     Notations:   string;
  455.     // Notation List, separated by pipe symbols '|'
  456.     AttrType:    TAttrType;        // Attribute Type
  457.     DefaultType: TAttrDefault;     // Default Type
  458.   end;
  459.   TElemDef = class(TNvpList)
  460.     // Represents a <!ELEMENT Definition. Is a list of TAttrDef-Nodes
  461.     Name:     string;            // Element name
  462.     ElemType: TElemType;         // Element type
  463.     Definition: string;            // Element definition from DTD
  464.   end;
  465.   TElemList = class(TObjectList)    // List of TElemDef nodes
  466.     function Node(Name: string): TElemDef;
  467.     procedure Add(Node: TElemDef);
  468.   end;
  469.   TEntityDef = class(TNvpNode)       // Represents a <!ENTITY Definition.
  470.     SystemId:     string;
  471.     PublicId:     string;
  472.     NotationName: string;
  473.   end;
  474.   TNotationDef = class(TNvpNode)
  475.     // Represents a <!NOTATION Definition. Value is the System ID
  476.     PublicId: string;
  477.   end;
  478.   TCharset = set of char;
  479. const
  480.   CWhitespace = [#32, #9, #13, #10];
  481.   // Whitespace characters (XmlSpec 2.3)
  482.   CLetter     = [#$41..#$5A, #$61..#$7A, #$C0..#$D6, #$D8..#$F6, #$F8..#$FF];
  483.   CDigit      = [#$30..#$39];
  484.   CNameChar   = CLetter + CDigit + ['.', '-', '_', ':', #$B7];
  485.   CNameStart  = CLetter + ['_', ':'];
  486.   CQuoteChar  = ['"', ''''];
  487.   CPubidChar  = [#32, ^M, ^J, #9, 'a'..'z', 'A'..'Z', '0'..'9',
  488.     '-', '''', '(', ')', '+', ',', '.', '/', ':',
  489.     '=', '?', ';', '!', '*', '#', '@', '$', '_', '%'];
  490.   CDStart = '<![CDATA[';
  491.   CDEnd   = ']]>';
  492.   // --- Name Constants for the above enumeration types
  493.   CPartType_Name: array [TPartType] of string =
  494.     ('', 'XML Prolog', 'Comment', 'PI',
  495.     'DTD Declaration', 'Start Tag', 'Empty Tag', 'End Tag',
  496.     'Text', 'CDATA');
  497.   CValueType_Name: array [TValueType] of string =
  498.     ('Normal', 'Implied', 'Fixed', 'Default');
  499.   CAttrDefault_Name: array [TAttrDefault] of string =
  500.     ('Default', 'Required', 'Implied', 'Fixed');
  501.   CElemType_Name: array [TElemType] of string =
  502.     ('Empty', 'Any', 'Childs only', 'Mixed');
  503.   CAttrType_Name: array [TAttrType] of string = ('Unknown', 'CDATA',
  504.     'ID', 'IDREF', 'IDREFS',
  505.     'ENTITY', 'ENTITIES',
  506.     'NMTOKEN', 'NMTOKENS',
  507.     'Notation', 'Enumeration');
  508. function ConvertWs(Source: string; PackWs: boolean): string;
  509. // Convert WS to spaces #x20
  510. procedure SetStringSF(var S: string; BufferStart, BufferFinal: PChar);
  511. // SetString by Start/Final of buffer
  512. function StrSFPas(Start, Finish: PChar): string;
  513. // Convert buffer part to Pascal string
  514. function TrimWs(Source: string): string;
  515. // Trim Whitespace
  516. function AnsiToUtf8(Source: ansistring): string;
  517. // Convert Win-1252 to UTF-8
  518. function Utf8ToAnsi(Source: string; UnknownChar: char = '