Menu

[r2058]: / trunk / Src / URSS20.pas  Maximize  Restore  History

Download this file

604 lines (551 with data), 18.7 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
{
* URSS20.pas
*
* Implements classes that encapsulate the information contained in an RSS 2.0
* XML document.
*
* $Rev$
* $Date$
*
* ***** BEGIN LICENSE BLOCK *****
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is URSS20.pas
*
* The Initial Developer of the Original Code is Peter Johnson
* (http://www.delphidabbler.com/).
*
* Portions created by the Initial Developer are Copyright (C) 2010 Peter
* Johnson. All Rights Reserved.
*
* Contributor(s)
* NONE
*
* ***** END LICENSE BLOCK *****
}
unit URSS20;
interface
uses
// Delphi
Generics.Defaults, Generics.Collections, XMLIntf,
// Project
UExceptions, UXMLDocumentEx;
type
{
TRSS20Item:
Encapsulates an RSS 2.0 item. Instances cannot be created and must not be
freed directly. Lifetimes are managed by TRSS20.
}
TRSS20Item = class abstract(TObject)
strict protected
function GetDescription: string; virtual; abstract;
{Read accessor for Description property.
@return Value of property.
}
function GetGUID: string; virtual; abstract;
{Read accessor for GUID property.
@return Value of property.
}
function GetGUIDIsPermalink: Boolean; virtual; abstract;
{Read accessor for GUIDIsPermalink property.
@return Value of property.
}
function GetLink: string; virtual; abstract;
{Read accessor for Link property.
@return Value of property.
}
function GetPubDateAsText: string; virtual; abstract;
{Read accessor for PubDate property.
@return Value of property.
}
function GetTitle: string; virtual; abstract;
{Read accessor for Title property.
@return Value of property.
}
function GetPermalink: string; virtual;
{Read accessor for Permalink property.
@return Value of property.
}
function GetPubDate: TDateTime; virtual;
{Read accessor for PubDate property.
@return Value of property.
}
public
property Title: string read GetTitle;
{The title of the item. May be '', but must be non-empty if Description is
''}
property Link: string read GetLink;
{The URL of complete story etc associated with the item. May be ''}
property Description: string read GetDescription;
{The item synopsis. May be '' but must be non-empty if Title is ''}
property GUID: string read GetGUID;
{A string that uniquely identifies the item. May by a URL (permalink). May
be ''}
property GUIDIsPermalink: Boolean read GetGUIDIsPermalink;
{True if GUID is a permalink, False if not}
property Permalink: string read GetPermalink;
{A unique link to the item. This is the same as GUID if GUIDIsPermalink is
True or '' if GUIDIsPermalink is False}
property PubDate: TDateTime read GetPubDate;
{Publication date of item in GMT (UTC). Set to midnight 01 Jan 1900 if no
date specified or if date string is invalid}
property PubDateAsText: string read GetPubDateAsText;
{Publication date of the item in RFC822 date format. May be ''}
end;
{
TRSS20:
Encapsulates and RSS 2.0 channel. The channel is loaded from an XML object
DOM. If there is more than one channel in the feed then only the first
channel is used.
}
TRSS20 = class(TObject)
strict private
fItems: TObjectList<TRSS20Item>; // Maintains list if items
fChannel: IXMLNode; // Reference to [first] channel element
function GetCopyright: string;
{Read accessor for Copyright property. Gets value from XML document.
@return Value of Copyright property.
}
function GetCount: Integer;
{Read accessor for Count property.
@return Number of items in XML document.
}
function GetDescription: string;
{Read accessor for Description property. Gets value from XML document.
@return Value of Description property.
}
function GetDocs: string;
{Read accessor for Docs property. Gets value from XML document.
@return Value of Docs property.
}
function GetItem(Idx: Integer): TRSS20Item;
{Read accessor for Items[] property.
@param Idx [in] Index of required item.
@return Reference to required item object.
}
function GetLanguage: string;
{Read accessor for Language property. Gets value from XML document.
@return Value of Language property.
}
function GetLink: string;
{Read accessor for Link property. Gets value from XML document.
@return Value of Link property.
}
function GetPubDate: TDateTime;
{Read accessor for PubDate property. Gets value from PubDateAsText
property.
@return Value of PubDate property.
}
function GetPubDateAsText: string;
{Read accessor for PubDateAsText property. Gets value from XML document.
@return Value of PubDateAsText property.
}
function GetTitle: string;
{Read accessor for Title property. Gets value from XML document.
@return Value of Title property.
}
strict protected
function FindChannelChildNode(const NodeName: string): IXMLNode;
{Finds a named child node of the "channel" node in the XML document.
@param NodeName [in] Name of required node.
@return Reference to required node or nil if not found.
}
function GetChannelChildNodeText(const NodeName: string): string;
{Gets the text of a named text element child node of the "channel" node in
the XML document.
@param NodeName [in] Name of required node.
@return The child node's text or '' if node not found or not a text
element.
}
public
constructor Create;
{Object constructor. Sets up an empty RSS object.
}
destructor Destroy; override;
{Object destructor. Tidies up object.
}
procedure Load(XMLDoc: IXMLDocumentEx);
{Loads RSS information from an XML Document DOM.
@param XMLDoc [in] DOM from which to read information.
}
function GetEnumerator: TEnumerator<TRSS20Item>;
{Create an enumerator for the object that enumerates all the news items.
@return Enumerator instance.
}
property Title: string read GetTitle;
{Name of the channel. Must be non-empty}
property Link: string read GetLink;
{URL of the HTML website corresponding to the channel. Must be non-empty}
property Description: string read GetDescription;
{Short description of the channel. Must be non-empty}
property Language: string read GetLanguage;
{Language the channel is written in. Uses language codes defined by
Netscape or W3C. May be empty}
property Copyright: string read GetCopyright;
{Copyright notice for the channel. May be empty}
property PubDate: TDateTime read GetPubDate;
{Publication date for the channel's in GMT (UTC). Set to midnight 01 Jan
1900 if no date specified or if date string is invalid}
property PubDateAsText: string read GetPubDateAsText;
{Publication date for the channel's content in RFC822 date format. May be
empty}
property Docs: string read GetDocs;
{A URL that points to the documentation for the format used in the RSS
file. May be empty}
property Items[Idx: Integer]: TRSS20Item read GetItem; default;
{Array of new items in the channel}
property Count: Integer read GetCount;
{Number of news items in the channel}
end;
{
ERSS20:
Class of exception raised by classes in this unit.
}
ERSS20 = class(ECodeSnip);
implementation
uses
// Delphi
SysUtils,
// Project
URFC2822Date;
type
{
TRSS20ItemImpl:
Concrete implementation of TRSS20Item that reads its properties from an
"item" node from the RSS feed's XML DOM.
}
TRSS20ItemImpl = class sealed(TRSS20Item)
strict private
fItemNode: IXMLNode; // Reference to XML item node
function FindChildNode(const NodeName: string): IXMLNode;
{Finds a named child node of the item node in the XML document.
@param NodeName [in] Name of required node.
@return Reference to required node or nil if not found.
}
function GetTextOfChildNode(const NodeName: string): string;
{Gets the text of a named text element child node of the "item" node in
the XML document.
@param NodeName [in] Name of required node.
@return The child node's text or '' if node not found or not a text
element.
}
strict protected
function GetDescription: string; override;
{Read accessor for Description property. Gets value from XML item node.
@return Value of Description property.
}
function GetGUID: string; override;
{Read accessor for GUID property. Gets value from XML item node.
@return Value of GUID property.
}
function GetGUIDIsPermalink: Boolean; override;
{Read accessor for GUIDIsPermalink property. Gets value from "guid" child
node.
@return Value of GUIDIsPermalink property.
}
function GetLink: string; override;
{Read accessor for Link property. Gets value from XML item node.
@return Value of Link property.
}
function GetPubDateAsText: string; override;
{Read accessor for PubDateAsText property. Gets value from XML item node.
@return Value of PubDateAsText property.
}
function GetTitle: string; override;
{Read accessor for Title property. Gets value from XML item node.
@return Value of Title property.
}
public
constructor Create(ItemNode: IXMLNode);
{Object constructor. Creates item instance that has properties of a
item node from XML document.
@param ItemNode [in] XML "item" node that contains required information.
}
destructor Destroy; override;
{Object desctructor. Tears down object.
}
end;
function DecodeDate(const DateStr: string): TDateTime;
{Decodes RFC2822 date string into TDateTime format in GMT. If date string is
empty or invalid a default date is used.
@param DateStr [in] RFC2822 date format string to be decoded.
@return GMT TDateTime equivalent value or default date value if date string
empty or invalid.
}
// ---------------------------------------------------------------------------
function DefaultDate: TDateTime;
{Provides a default date.
@return Default date of midnight, 01 Jan 1900.
}
begin
Result := EncodeDate(1900, 1, 1);
end;
// ---------------------------------------------------------------------------
begin
if DateStr <> '' then
begin
try
Result := RFC2822DateToGMTDateTime(DateStr);
except
Result := DefaultDate;
end;
end
else
Result := DefaultDate;
end;
{ TRSS20 }
constructor TRSS20.Create;
{Object constructor. Sets up an empty RSS object.
}
begin
inherited Create;
fItems := TObjectList<TRSS20Item>.Create(True);
end;
destructor TRSS20.Destroy;
{Object destructor. Tidies up object.
}
begin
fItems.Free; // frees owned item objects
inherited;
end;
function TRSS20.FindChannelChildNode(const NodeName: string): IXMLNode;
{Finds a named child node of the "channel" node in the XML document.
@param NodeName [in] Name of required node.
@return Reference to required node or nil if not found.
}
begin
Result := fChannel.ChildNodes.FindNode(NodeName);
end;
function TRSS20.GetChannelChildNodeText(const NodeName: string): string;
{Gets the text of a named text element child node of the "channel" node in the
XML document.
@param NodeName [in] Name of required node.
@return The child node's text or '' if node not found or not a text element.
}
var
Node: IXMLNode; // named child node
begin
Node := FindChannelChildNode(NodeName);
if Assigned(Node) and (Node.IsTextElement) then
Result := Node.Text
else
Result := '';
end;
function TRSS20.GetCopyright: string;
{Read accessor for Copyright property. Gets value from XML document.
@return Value of Copyright property.
}
begin
Result := GetChannelChildNodeText('copyright');
end;
function TRSS20.GetCount: Integer;
{Read accessor for Count property.
@return Number of items in XML document.
}
begin
Result := fItems.Count;
end;
function TRSS20.GetDescription: string;
{Read accessor for Description property. Gets value from XML document.
@return Value of Description property.
}
begin
Result := GetChannelChildNodeText('description');
end;
function TRSS20.GetDocs: string;
{Read accessor for Docs property. Gets value from XML document.
@return Value of Docs property.
}
begin
Result := GetChannelChildNodeText('docs');
end;
function TRSS20.GetEnumerator: TEnumerator<TRSS20Item>;
{Create an enumerator for the object that enumerates all the news items.
@return Enumerator instance.
}
begin
Result := fItems.GetEnumerator;
end;
function TRSS20.GetItem(Idx: Integer): TRSS20Item;
{Read accessor for Items[] property.
@param Idx [in] Index of required item.
@return Reference to required item object.
}
begin
Result := fItems[Idx];
end;
function TRSS20.GetLanguage: string;
{Read accessor for Language property. Gets value from XML document.
@return Value of Language property.
}
begin
Result := GetChannelChildNodeText('language');
end;
function TRSS20.GetLink: string;
{Read accessor for Link property. Gets value from XML document.
@return Value of Link property.
}
begin
Result := GetChannelChildNodeText('link');
end;
function TRSS20.GetPubDate: TDateTime;
{Read accessor for PubDate property. Gets value from PubDateAsText property.
@return Value of PubDate property.
}
begin
Result := DecodeDate(PubDateAsText);
end;
function TRSS20.GetPubDateAsText: string;
{Read accessor for PubDateAsText property. Gets value from XML document.
@return Value of PubDateAsText property.
}
begin
Result := GetChannelChildNodeText('pubDate');
end;
function TRSS20.GetTitle: string;
{Read accessor for Title property. Gets value from XML document.
@return Value of Title property.
}
begin
Result := GetChannelChildNodeText('title');
end;
procedure TRSS20.Load(XMLDoc: IXMLDocumentEx);
{Loads RSS information from an XML Document DOM.
@param XMLDoc [in] DOM from which to read information.
}
resourcestring
// Error message
sInvalidDoc = 'Invalid RSS document';
var
ItemNodes: IXMLSimpleNodeList; // list of items nodes of channel
ItemNode: IXMLNode; // each item in ItemNodes
begin
fItems.Clear;
fChannel := XMLDoc.FindNode('rss\channel');
if not Assigned(fChannel) then
raise ERSS20.Create(sInvalidDoc);
// create items
ItemNodes := XMLDoc.FindChildNodes(fChannel, 'item');
for ItemNode in ItemNodes do
fItems.Add(TRSS20ItemImpl.Create(ItemNode));
end;
{ TRSS20Item }
function TRSS20Item.GetPermalink: string;
{Read accessor for Permalink property.
@return Value of property.
}
begin
// Calculates value from other properties
if GUIDIsPermalink then
Result := GUID
else
Result := '';
end;
function TRSS20Item.GetPubDate: TDateTime;
{Read accessor for PubDate property.
@return Value of property.
}
begin
// Calculates value from PubDateAsText property
Result := DecodeDate(PubDateAsText);
end;
{ TRSS20ItemImpl }
constructor TRSS20ItemImpl.Create(ItemNode: IXMLNode);
{Object constructor. Creates item instance that has properties of a specified
item node from XML document.
@param ItemNode [in] XML "item" node that contains required information.
}
begin
inherited Create;
fItemNode := ItemNode;
end;
destructor TRSS20ItemImpl.Destroy;
{Object desctructor. Tears down object.
}
begin
fItemNode := nil;
inherited;
end;
function TRSS20ItemImpl.FindChildNode(const NodeName: string): IXMLNode;
{Finds a named child node of the item node in the XML document.
@param NodeName [in] Name of required node.
@return Reference to required node or nil if not found.
}
begin
Result := fItemNode.ChildNodes.FindNode(NodeName);
end;
function TRSS20ItemImpl.GetDescription: string;
{Read accessor for Description property. Gets value from XML item node.
@return Value of Description property.
}
begin
Result := GetTextOfChildNode('description');
end;
function TRSS20ItemImpl.GetGUID: string;
{Read accessor for GUID property. Gets value from XML item node.
@return Value of GUID property.
}
begin
Result := GetTextOfChildNode('guid');
end;
function TRSS20ItemImpl.GetGUIDIsPermalink: Boolean;
{Read accessor for GUIDIsPermalink property. Gets value from "guid" child
node.
@return Value of GUIDIsPermalink property.
}
var
Node: IXMLNode; // reference to "guid" node
begin
Node := FindChildNode('guid');
if not Assigned(Node) then
Exit(False);
if not Node.HasAttribute('isPermaLink') then
Exit(True); // isPermaLink is optional and defaults to true
Result := Node.Attributes['isPermaLink'] = 'true';
end;
function TRSS20ItemImpl.GetLink: string;
{Read accessor for Link property. Gets value from XML item node.
@return Value of Link property.
}
begin
Result := GetTextOfChildNode('link');
end;
function TRSS20ItemImpl.GetPubDateAsText: string;
{Read accessor for PubDateAsText property. Gets value from XML item node.
@return Value of PubDateAsText property.
}
begin
Result := GetTextOfChildNode('pubDate');
end;
function TRSS20ItemImpl.GetTextOfChildNode(const NodeName: string): string;
{Gets the text of a named text element child node of the "item" node in the
XML document.
@param NodeName [in] Name of required node.
@return The child node's text or '' if node not found or not a text element.
}
var
Node: IXMLNode;
begin
Node := FindChildNode(NodeName);
if Assigned(Node) and (Node.IsTextElement) then
Result := Node.Text
else
Result := '';
end;
function TRSS20ItemImpl.GetTitle: string;
{Read accessor for Title property. Gets value from XML item node.
@return Value of Title property.
}
begin
Result := GetTextOfChildNode('title');
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.