extjsxml.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019 by the Free Pascal development team
  4. extjs xml
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit extjsxml;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, httpdefs, fpextjs, dom, xmlread, xmlwrite, fpwebdata, db;
  16. Type
  17. { TExtJSXMLWebdataInputAdaptor }
  18. TExtJSXMLWebdataInputAdaptor = CLass(TCustomWebdataInputAdaptor)
  19. private
  20. FDE: String;
  21. FRE: String;
  22. FREEL: String;
  23. FXML : TXMLDocument;
  24. FDocRoot : TDOMElement;
  25. FRoot : TDOMElement;
  26. FCurrentRow : TDOMElement;
  27. FIDValue : TDOMElement;
  28. function isDocumentStored: boolean;
  29. function IsRecordStored: boolean;
  30. function isRootStored: boolean;
  31. function CheckData: Boolean;
  32. protected
  33. Public
  34. Constructor Create(AOwner : TComponent); override;
  35. Destructor destroy; override;
  36. Function TryFieldValue(Const AFieldName : String; out AValue : String) : Boolean; override;
  37. Property DocumentElement : String Read FDE Write FDE stored isDocumentStored;
  38. Property RootElement : String Read FRE Write FRE stored isRootStored;
  39. Property RecordElement : String Read FREEL Write FREEL stored IsRecordStored;
  40. end;
  41. { TExtJSJSONDataFormatter }
  42. { TExtJSXMLDataFormatter }
  43. TXMLElementEvent = Procedure (Sender : TObject; AElement : TDOMElement) of object;
  44. TXMLExceptionObjectEvent = Procedure(Sender : TObject; E : Exception; AResponse : TDOMElement) of Object;
  45. TExtJSXMLDataFormatter = Class(TExtJSDataFormatter)
  46. private
  47. FAfterDataToXML: TXMLElementEvent;
  48. FAfterRowToXML: TXMLElementEvent;
  49. FBeforeDataToXML: TXMLElementEvent;
  50. FBeforeRowToXML: TXMLElementEvent;
  51. FDP: String;
  52. FOnErrorResponse: TXmlExceptionObjectEvent;
  53. FReP: String;
  54. FRP: String;
  55. function IsDocumentStored: boolean;
  56. function IsRecordStored: boolean;
  57. function IsRootStored: boolean;
  58. protected
  59. Function CreateAdaptor(ARequest : TRequest) : TCustomWebdataInputAdaptor; override;
  60. Procedure DoExceptionToStream(E : Exception; ResponseContent : TStream); override;
  61. Function GetDataContentType : String; override;
  62. function RowToXML(Doc: TXMLDocument): TDOMelement;
  63. Procedure DoBeforeRow(ARow : TDOMElement); virtual;
  64. Procedure DoAfterRow(ARow : TDOMElement); virtual;
  65. Procedure DoBeforeData(Data : TDOMElement); virtual;
  66. Procedure DoAfterData(Data: TDOMElement); virtual;
  67. procedure DatasetToStream(Stream: TStream); override;
  68. public
  69. Constructor Create(AOwner : TComponent); override;
  70. published
  71. Property RootProperty : String Read FRP Write FRP Stored IsRootStored;
  72. Property RecordProperty : String Read FReP Write FReP Stored IsRecordStored;
  73. Property DocumentProperty : String Read FDP Write FDP Stored IsDocumentStored;
  74. // Called before row element (passed to handler) is filled with fields.
  75. Property BeforeRowToXML : TXMLElementEvent Read FBeforeRowToXML Write FBeforeRowToXML;
  76. // Called after row element (passed to handler) was filled with fields.
  77. Property AfterRowToXML : TXMLElementEvent Read FAfterRowToXML Write FAfterRowToXML;
  78. // Called before any rows are added to root element (passed to handler).
  79. Property BeforeDataToXML : TXMLElementEvent Read FBeforeDataToXML Write FBeforeDataToXML;
  80. // Called after all rows are appended to root element (passed to handler).
  81. Property AfterDataToXML : TXMLElementEvent Read FAfterDataToXML Write FAfterDataToXML;
  82. // Called when an exception is caught and formatted.
  83. Property OnErrorResponse : TXmlExceptionObjectEvent Read FOnErrorResponse Write FOnErrorResponse;
  84. end;
  85. implementation
  86. { $define wmdebug}
  87. {$ifdef wmdebug}
  88. uses dbugintf;
  89. {$endif wmdebug}
  90. Resourcestring
  91. SerrNoExceptionMessage = 'No exception to take error message from.';
  92. Const
  93. // For TExtJSXMLDataFormatter.
  94. SDefDocumentProperty = 'xrequest';
  95. SDefRecordProperty = 'row';
  96. SDefRootProperty = 'dataset';
  97. // Fpr TExtJSXMLWebdataInputAdaptor
  98. SDefRootElement = SDefRootProperty;
  99. SDefRecordElement = SDefRecordProperty;
  100. SDefDocumentElement = SDefDocumentProperty;
  101. function TExtJSXMLDataFormatter.IsRootStored: boolean;
  102. begin
  103. Result:=RootProperty<>SDefRootProperty;
  104. end;
  105. function TExtJSXMLDataFormatter.CreateAdaptor(ARequest: TRequest
  106. ): TCustomWebdataInputAdaptor;
  107. Var
  108. R : TExtJSXMLWebdataInputAdaptor;
  109. begin
  110. R:=TExtJSXMLWebdataInputAdaptor.Create(Self);
  111. R.Request:=ARequest;
  112. R.DocumentElement:=Self.DocumentProperty;
  113. R.RootElement:=Self.RootProperty;
  114. R.RecordElement:=Self.RecordProperty;
  115. Result:=R;
  116. end;
  117. function TExtJSXMLDataFormatter.IsRecordStored: boolean;
  118. begin
  119. Result:=RecordProperty<>SDefRecordProperty;
  120. end;
  121. function TExtJSXMLDataFormatter.IsDocumentStored: boolean;
  122. begin
  123. Result:=DocumentProperty<>SDefDocumentProperty
  124. end;
  125. procedure TExtJSXMLDataFormatter.DoExceptionToStream(E: Exception;
  126. ResponseContent: TStream);
  127. Var
  128. Xml : TXMLDocument;
  129. El,C : TDOMElement;
  130. begin
  131. XML:=TXMLDocument.Create;
  132. try
  133. El:=XML.CreateElement(RootProperty);
  134. XML.AppendChild(El);
  135. El[SuccessProperty]:='false';
  136. C:=XML.CreateElement(SuccessProperty);
  137. C.AppendChild(XML.CreateTextNode('false'));
  138. El.AppendChild(c);
  139. C:=XML.CreateElement(MessageProperty);
  140. El.AppendChild(C);
  141. If Assigned(E) then
  142. C.AppendChild(XML.CreateTextNode(E.Message))
  143. else
  144. C.AppendChild(XML.CreateTextNode(SerrNoExceptionMessage));
  145. If Assigned(FOnErrorResponse) then
  146. FOnErrorResponse(Self,E,El);
  147. WriteXMLFile(XML,ResponseContent);
  148. Finally
  149. XML.Free;
  150. end;
  151. end;
  152. function TExtJSXMLDataFormatter.GetDataContentType: String;
  153. begin
  154. Result:='text/xml';
  155. end;
  156. Function TExtJSXMLDataFormatter.RowToXML(Doc : TXMLDocument) : TDOMelement;
  157. Var
  158. E : TDOMElement;
  159. F : TField;
  160. I : Integer;
  161. S : String;
  162. begin
  163. Result:=Doc.CreateElement(RecordProperty);
  164. try
  165. DoBeforeRow(Result);
  166. For I:=0 to Dataset.Fields.Count-1 do
  167. begin
  168. F:=Dataset.Fields[i];
  169. E:=Doc.CreateElement(F.FieldName);
  170. If F.DataType in [ftMemo, ftFmtMemo, ftWideMemo, ftBlob ] then
  171. S:=F.AsString
  172. else
  173. S:=F.DisplayText;
  174. If (OnTranscode<>Nil) then
  175. OnTranscode(Self,F,S,True);
  176. E.AppendChild(Doc.CreateTextNode(S));
  177. Result.AppendChild(E);
  178. end;
  179. DoAfterRow(Result);
  180. except
  181. Result.Free;
  182. Raise;
  183. end;
  184. end;
  185. procedure TExtJSXMLDataFormatter.DoBeforeRow(ARow: TDOMElement);
  186. begin
  187. If Assigned(FBEforeRowToXml) then
  188. FBEforeRowToXml(Self,ARow);
  189. end;
  190. procedure TExtJSXMLDataFormatter.DoAfterRow(ARow: TDOMElement);
  191. begin
  192. If Assigned(FAfterRowToXml) then
  193. FAfterRowToXml(Self,ARow);
  194. end;
  195. procedure TExtJSXMLDataFormatter.DoBeforeData(Data: TDOMElement);
  196. begin
  197. If Assigned(FBeforeDataToXML) then
  198. FBeforeDataToXML(Self,Data);
  199. end;
  200. procedure TExtJSXMLDataFormatter.DoAfterDAta(Data: TDOMElement);
  201. begin
  202. If Assigned(FAfterDataToXML) then
  203. FAfterDataToXML(Self,Data);
  204. end;
  205. procedure TExtJSXMLDataFormatter.DatasetToStream(Stream: TStream);
  206. Var
  207. Xml : TXMLDocument;
  208. E,C : TDOMElement;
  209. i,RCount,ACount : Integer;
  210. DS : TDataset;
  211. begin
  212. RCount:=0;
  213. ACount:=0;
  214. DS:=Dataset;
  215. XML:=TXMLDocument.Create;
  216. try
  217. E:=XML.CreateElement(RootProperty);
  218. XML.AppendChild(E);
  219. DoBeforeData(E);
  220. // Go to start
  221. ACount:=PageStart;
  222. While (Not DS.EOF) and (ACount>0) do
  223. begin
  224. DS.Next;
  225. Dec(ACount);
  226. Inc(RCount);
  227. end;
  228. ACount:=PageSize;
  229. While (not DS.EOF) and ((PageSize=0) or (ACount>0)) do
  230. begin
  231. Inc(RCount);
  232. Dec(ACount);
  233. E.AppendChild(RowToXML(XML));
  234. DS.Next;
  235. end;
  236. If (PageSize>0) then
  237. While (not DS.EOF) do
  238. begin
  239. Inc(RCount);
  240. DS.Next;
  241. end;
  242. C:=XML.CreateElement(TotalProperty);
  243. C.AppendChild(XML.CreateTextNode(IntToStr(RCount)));
  244. E.AppendChild(C);
  245. C:=XML.CreateElement(SuccessProperty);
  246. C.AppendChild(XML.CreateTextNode('true'));
  247. E.AppendChild(C);
  248. DoAfterData(E);
  249. WriteXMLFile(XML,Stream);
  250. finally
  251. XML.Free;
  252. end;
  253. end;
  254. constructor TExtJSXMLDataFormatter.Create(AOwner: TComponent);
  255. begin
  256. inherited Create(AOwner);
  257. RootProperty:=SDefRootProperty;
  258. RecordProperty:=SDefRecordProperty;
  259. DocumentProperty:=SDefDocumentProperty
  260. end;
  261. { TExtJSXMLWebdataInputAdaptor }
  262. function TExtJSXMLWebdataInputAdaptor.isDocumentStored: boolean;
  263. begin
  264. Result:=DocumentElement<>SDefDocumentElement;
  265. end;
  266. function TExtJSXMLWebdataInputAdaptor.IsRecordStored: boolean;
  267. begin
  268. Result:=RecordElement<>SDefRecordElement;
  269. end;
  270. function TExtJSXMLWebdataInputAdaptor.isRootStored: boolean;
  271. begin
  272. Result:=RootElement<>SDefRootElement;
  273. end;
  274. function TExtJSXMLWebdataInputAdaptor.CheckData: Boolean;
  275. Var
  276. S : String;
  277. T : TStringSTream;
  278. E : TDomElement;
  279. P : Integer;
  280. begin
  281. {$ifdef wmdebug}senddebug('Check data: '+Request.Content);{$endif}
  282. Result:=Assigned(FXML);
  283. If Not (Result) then
  284. begin
  285. S:=Request.ContentType;
  286. P:=Pos(';',S);
  287. If (P<>0) then
  288. S:=Copy(S,1,P-1);
  289. {$ifdef wmdebug}senddebug('Check data: '+S);{$endif}
  290. Result:=CompareText(S,'application/x-www-form-urlencoded')=0;
  291. If not Result then
  292. begin
  293. T:=TStringStream.Create(Request.Content);
  294. try
  295. XmlRead.ReadXMLFile(FXML,T);
  296. If (DocumentElement<>'') and (FXML.DocumentElement.NodeName=DocumentElement) then
  297. begin
  298. {$ifdef wmdebug}senddebug('Document element is ExtJS DocumentElement');{$endif}
  299. FDocRoot:=FXML.DocumentElement;
  300. E:=FDocRoot;
  301. end
  302. else if (DocumentElement<>'') then
  303. begin
  304. //FXML.
  305. {$ifdef wmdebug}senddebug('Looking for ExtJS Documentelement "'+DocumentElement+'" in XML.DocumentElement');{$endif}
  306. FDocRoot:=FXML.DocumentElement.FindNode(DocumentElement) as TDOMElement;
  307. E:=FDocRoot;
  308. end;
  309. {$ifdef wmdebug}senddebug('Looking for DocRoot element "'+RootElement+'" in FDocRoot');{$endif}
  310. If Assigned(FDocRoot) then
  311. FRoot:=FDocRoot
  312. else
  313. FRoot:=FXML.FindNode(RootElement) as TDomElement;
  314. {$ifdef wmdebug}senddebug('Looking for current record element "'+RecordElement+'" in FRoot');{$endif}
  315. If Assigned(FRoot) then
  316. begin
  317. FCurrentRow:=FRoot.FindNode(RecordElement) as TDomElement;
  318. If Not Assigned(FCurrentRow) then
  319. FIDValue:=FRoot.FindNode('ID') as TDomElement;
  320. end
  321. else
  322. begin
  323. {$ifdef wmdebug}senddebug('Looking for current record element "'+RecordElement+'" in document');{$endif}
  324. FCurrentRow:=FXML.FindNode(RecordElement) as TDomElement;
  325. end;
  326. If (FCurrentRow=Nil) and (FXML.DocumentElement.NodeName=RecordElement) then
  327. begin
  328. {$ifdef wmdebug}senddebug('Documentelement is record element "'+RecordElement+'"');{$endif}
  329. FCurrentRow:=FXML.DocumentElement;
  330. end;
  331. {$ifdef wmdebug}senddebug('Have current row: "'+IntToStr(Ord(Assigned(FCurrentRow)))+'"');{$endif}
  332. Result:=True;
  333. finally
  334. T.free;
  335. end;
  336. end;
  337. end;
  338. end;
  339. function TExtJSXMLWebdataInputAdaptor.TryFieldValue(const AFieldName: String;
  340. out AValue: String): Boolean;
  341. Var
  342. I : Integer;
  343. E : TDOMElement;
  344. N : TDOMNode;
  345. begin
  346. Result:=False;
  347. if CheckData then
  348. begin
  349. If Assigned(FIDValue) and (0=CompareText(AFieldName,'ID')) then
  350. begin
  351. AValue:=FIDValue.NodeValue;
  352. Result:=True;
  353. end
  354. else if Assigned(FCurrentRow) then
  355. begin
  356. E:=FCurrentRow.FindNode(AFieldName) as TDomElement;
  357. Result:=Assigned(E);
  358. if result then
  359. begin
  360. N:=E.FirstChild;
  361. If Assigned(N) then
  362. AValue:=N.NodeValue;
  363. end;
  364. end;
  365. end;
  366. end;
  367. constructor TExtJSXMLWebdataInputAdaptor.Create(AOwner: TComponent);
  368. begin
  369. inherited Create(AOwner);
  370. RootElement:=SDefRootElement;
  371. RecordElement:=SDefRecordElement;
  372. DocumentElement:=SDefDocumentElement;
  373. end;
  374. destructor TExtJSXMLWebdataInputAdaptor.destroy;
  375. begin
  376. FreeAndNil(FXML);
  377. inherited destroy;
  378. end;
  379. initialization
  380. WebDataProviderManager.RegisterInputAdaptor('ExtJS - XML',TExtJSXMLWebdataInputAdaptor);
  381. WebDataProviderManager.RegisterDataProducer('ExtJS - XML',TExtJSXMLDataFormatter);
  382. finalization
  383. WebDataProviderManager.UnRegisterInputAdaptor('ExtJS - XML');
  384. WebDataProviderManager.UnRegisterDataProducer('ExtJS - XML')
  385. end.