FINALLY ITS EASY TO CREATE AND READ XML FILES

GENERATE DELPHI SUPPORT FOR READING BY KIM MADSEN AND WRITING XML FILES PAGE 1 - THAT ADHERE TO THE GOOGLE MERCHANTS RATING DATA SPECIFICATIONS

starter

expert Delphi

This article is actually less about how Google Merchants ratings work, and more about the principle of utilizing kbmMW to convert XSD (XML schema documents) to easily streamable Delphi objects. kbmMW Enterprise Edition includes a complete XSD schema converter, which takes an xsd file as input and outputs readily compilable Pascal objects, that are very easy to read, alter and stream to and from XML and JSON.

First download the XSD from Google here: merchant-review-feeds/schema Next one have to compile (if not already done) and run the kbmMW ConvertXSD.exe application. Now click Convert XSD file, and select the downloaded merchant_reviews.xsd file. A split second later, the file has been read, validated and a merchant_reviews.pas file has been generated in the same directory.

First a little bit about the XSD schema converter. Its delivered as a demo application (that is full featured in what it does), but which can be tailored if required to any developers need. Its main internal components, are a TkbmMWXSDParser class (with a number of assistant classes), a TkbmMWXSDPascalCodeGen class (descending from TkbmMWXSDCustomCodeGen) and of course the TkbmMWDOMXML class for speedy and complete handling of the XML, in which XSD files are written.

As can be seen, it's actually possible to utilize the parse tree generated by the XSD parser to output other types documents by inheriting from the TkbmMWXSDCustomCodeGen. That's however out of scope for this article. I've done some comparisons with the built in XSD importer tool in Delphi, and find that the kbmMW ConvertXSD tool is better and more accurate in converting XSD documents, and easily converts XSD documents not possible using Embarcaderos XSD inporter. The outset for this article is to generate Delphi support for reading and writing XML files that adhere to the Google merchants rating data specifications.

In the right pane, it's possible to see which classes kbmMW's XSD converter have found. And in the left pane, any warnings or errors would have been listed.

FINALLY ITS EASY TO CREATE AND READ

XML FILES

Issue Nr 3 2015 BLAISE PASCAL MAGAZINE

43

GENERATE DELPHI SUPPORT FOR READING AND WRITING XML FILES PAGE 2

unit merchant_reviews;

The converted file looks like this (snippets only shown):

// ========================================================================== // Generated by kbmMW XSD Converter // 5/11/2015 01:08:59 // Based on: C:\svn_c4d\kbmmw\trunk\ConvertXSD\GoogleMerchantFeedback\merchant_reviews.xsd // ==========================================================================

// Log: // Converted without errors or warnings.

...

type

(*$HPPEMIT 'namespace Merchant_reviews {'*) {$SCOPEDENUMS ON}

TLanguageCode = (aa,ab,ae,af,ak,am,an,ar,&as,av,ay,az,ba,be,bg,bh,bi,bm,bn,bo,br,bs,ca,ce,ch,co,cr,cs,cu,cv,cy,da,de,dv,dz,ee,el,en ,eo,es,et,eu,fa,ff,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,gv,ha,he,hi,ho,hr,ht,hu,hy,hz,ia,id,ie,ig,ii,ik,io,&is,it,iu,ja,jv ,ka,kg,ki,kj,kk,kl,km,kn,ko,kr,ks,ku,kv,kw,ky,la,lb,lg,li,ln,lo,lt,lu,lv,mg,mh,mi,mk,ml,mn,mr,ms,mt,my,na,nb,nd,ne, ng,nl,nn,no,nr,nv,ny,oc,oj,om,&or,os,pa,pi,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sc,sd,se,sg,si,sk,sl,sm,sn,so,sq,sr,ss,st, su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,&to,tr,ts,tt,tw,ty,ug,uk,ur,uz,ve,vi,vo,wa,wo,xh,yi,yo,za,zh,zu);

TCountryCode =

... Ttype_1 = (singleton,group); TNonEmptyString = kbmMWNullable; Ttype = (summary,detail); Treviewer_type = (user,editorial,aggregator); Tcollection_method = (unsolicited,point_of_sale,after_fulfillment);

const CLanguageCode : array[TLanguageCode] of string =

('aa','ab','ae','af','ak','am','an','ar','as','av','ay','az','ba','be','bg','bh','bi','bm','bn','bo','br','bs','ca' ,'ce','ch','co','cr','cs','cu','cv','cy','da','de','dv','dz','ee','el','en','eo','es','et','eu','fa','ff','fi','fj' ,'fo','fr','fy','ga','gd','gl','gn','gu','gv','ha','he','hi','ho','hr','ht','hu','hy','hz','ia','id','ie','ig','ii' ,'ik','io','is','it','iu','ja','jv','ka','kg','ki','kj','kk','kl','km','kn','ko','kr','ks','ku','kv','kw','ky','la' ,'lb','lg','li','ln','lo','lt','lu','lv','mg','mh','mi','mk','ml','mn','mr','ms','mt','my','na','nb','nd','ne','ng' ,'nl','nn','no','nr','nv','ny','oc','oj','om','or','os','pa','pi','pl','ps','pt','qu','rm','rn','ro','ru','rw','sa' ,'sc','sd','se','sg','si','sk','sl','sm','sn','so','sq','sr','ss','st','su','sv','sw','ta','te','tg','th','ti','tk' ,'tl','tn','to','tr','ts','tt','tw','ty','ug','uk','ur','uz','ve','vi','vo','wa','wo','xh','yi','yo','za','zh','zu' );

CCountryCode : array[TCountryCode] of string = ...

Ctype_1 : array[Ttype_1] of string = ('singleton','group'); Ctype : array[Ttype] of string = ('summary','detail'); Creviewer_type : array[Treviewer_type] of string = ('user','editorial','aggregator'); Ccollection_method : array[Tcollection_method] of string = ('unsolicited','point_of_sale','after_fulfillment');

...

[kbmMW_Root('Review',[mwrfIncludeOnlyTagged])]

When one is creating a project that needs to read or write XML files that adhere to the Google merchants ratings XSD, one simply need to include this file in the uses clause, and then use kbmMW's serialization and deserialization methods to convert XML or JSON to objects or objects to XML or JSON. At merchant-review-feeds/sample there is a sample XML file provided by Google, which we will use to see that we can convert the XML to objects.

A new VCL application is created (it could be a Firemonkey application too, kbmMW works in both environments).

44

Issue Nr 3 2015 BLAISE PASCAL MAGAZINE

GENERATE DELPHI SUPPORT FOR READING AND WRITING XML FILES PAGE 3

In its uses clause we add the generated merchant_review unit:

uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, merchant_reviews;

Before serializing or deserializing we need to let kbmMW know about the classes that are part of the merchant_reviews unit. This is done in the OnFormCreate event in this sample:

kbmMW have full support for timezones, and you can operate the TkbmMWDateTime in much the same way as you would with a TDateTime. Ok.. then let us try to serialize the FFeed object

procedure TForm1.FormCreate(Sender: TObject); begin

Tmerchant_reviews.RegisterStreamableObjects; end;

back to XML again potentially after we have made changes to it, or perhaps even built a new Tfeed instance from scratch.

Now everything is ready for streaming. Lets put some code in the load XML buttons event handler to load a Google merchants ratings XML file and have it

procedure TForm1.btnSaveClick(Sender: TObject); var xmlm:TkbmMWXMLMarshal; xml:TkbmMWDOMXML; begin

if FFeed=nil then exit;

accessible via standard Delphi objects:

xmlm:=TkbmMWXMLMarshal.Create;

procedure TForm1.btnLoadClick(Sender: TObject); var

xmlm:TkbmMWXMLMarshal; xml:TkbmMWDOMXML; m:TMerchant; r:TReview; d:TNonEmptyString; begin xml:=TkbmMWDOMXML.Create;

try xml.LoadFromFile('merchant_reviews.xml' ); xmlm:=TkbmMWXMLMarshal.Create; try FFeed:=TFeed(xmlm.ValueFromDOMXML(TFeed,xml));

try xmlm.Typed:=false; xml:=xmlm.ValueToDOMXML(FFeed); if xml=nil then begin Memo1.Lines.Add('xml=null'); exit; end;

finally xmlm.Free;

end;

... Use the FFeed object for what you want.

xml.Typed:=false;

finally xmlm.Free;

xml.AutoIndent:=true;

end;

xml.AutoLineFeed:=true;

finally xml.Free;

end;

xml.Update; xml.SaveToFile('newfeed.xml'); xml.Free;

end;

It's that simple to convert the XML to true Delphi objects! Now you can access all fields/attributes like this:

Memo1.Lines.Add('FFeed.merchant.review.reviewer_id='+r.reviewer_id.ValueOr['']); Memo1.Lines.Add('FFeed.merchant.review.reviewer_type='+Creviewer_type[r.reviewer_type]); Memo1.Lines.Add('FFeed.merchant.review.review_date='+r.review_date.ISO8601String); Memo1.Lines.Add('FFeed.merchant.review.is_spam='+BoolToStr(r.is_spam.ValueOr[false]));

Notice the optional use of .ValueOr[...]. The reason is that for example reviewer_id is a nullable value. kbmMW understands the difference between for example a null string value and an empty string. Similarly kbmMW understands nullable integers, singles, doubles, Booleans, dates, times, date/times etc. Also notice the access of the review_date property. We want to display it as an ISO8601 formatted string in this case, but we could also have asked it to be shown as a RFC1123 formattet string instead or as a local date/time or as a GMT date/time.

It's as simple as that! Now a newfeed.xml file will have been generated based on the FFeed object. It will be data wise exact the same as the original xml file we deserialized, although it may differ in order or in filtering out empty XML nodes. What if you would want to send the Ffeed object instance to a browser, connected to a kbmMW application server that is acting as a web server? The browser usually understands Javascript, and often jQuery is used for sending requests to a webserver and receiving responses in what is called an AJAX operation (Async Javascript and XML).

Issue Nr 3 2015 BLAISE PASCAL MAGAZINE

45

GENERATE DELPHI SUPPORT FOR READING AND WRITING XML FILES PAGE 4

As such, the browser typically do support parsing XML to an extent, potentially via 3rdparty XML Javascript libraries. However Javascript supports a native textual object notation, that is more compact than XML and faster for it to read. JSON is the name for that notation (Javascript Object Notation). So a better choice is to serialize the Ffeed object to JSON and send that JSON stream to the browser. The browser would see the streamed data as true Javascript objects upon reception. In kbmMW it's simple to serialize to JSON:

procedure TForm1.btnSaveJSONClick(Sender: TObject); var jm:TkbmMWJSONMarshal; s:string; begin

if FFeed=nil then exit;

jm:=TkbmMWJSONMarshal.Create; try

s:=jm.ValueToString(FFeed);

Now the string s contains the JSON data

finally jm.Free; end; end;

The string can be sent directly to the browser as a response to the browsers GET or POST request, giving the mimetype application/json. What makes the serialization/deserialization magic happen is the combination of attributes given on the Delphi types, and an advanced and intelligent built in mechanism that understands the combination of attributes and the type and relations between the defined Delphi types that are to be serialized/deserialized. kbmMW's serializer is probably one of the most

advanced on the market, and is even included in the free kbmMW CodeGear Edition. A Delphi class can be decorated with a number of attributes that hints to the serializer/deserializer how it should go about its operation. This is a short explanation of the basic forms of various attributes currently understood by kbmMW:

[kbmMW_Ignore]

Can be placed in front of any field or property to ensure that that particular field/property is not serialized. Eg.

[kbmMW_Ignore] property SomeValue:string read....

[kbmMW_NotNull]

Can be placed in front of any field/property to indicate that the field must NOT take the value of NULL (undefined).

If it does, an exception will be raised upon serialization or deserialization.

[kbmMW_Element(..)] Place in front of any field/property to indicate that the value should be serialized as an element (a child node in XML).

Its also possible to specify the name of the child object like this: [kbmMW_Element('someName')]

[kbmMW_Attribute(..)] Similar to the kbmMW_Element, except that it directs that the value must be put in an attribute (in the parent node in

XML). For JSON it will work the same as kbmMW_Element. This attribute also accepts a naming argument.

[kbmMW_Root(..)]

Specifies default naming of a class, and what parts of it should automatically be serialized/deserialized like all published

properties, all public properties or only properties/fields tagged with kbmMW_Attribute or kbmMW_Element attributes.

[kbmMW_Null(..)]

Indicate that the element can take the value of NULL. Optionally a default value can be provided, which will be used in

case the value in the XML/JSON indicates NULL.

[kbmMW_Validate(...)] Validates a property/field or a complete class instance for its values and raises an exception if a value is out of spec.

A complete expression which can refer to any field in the class can be given. If the expression evaluates to false,

then an exception will be raised upon serialization/deserialization time.

Eg. [kbmMW_Validate('$someName=22')] accepts only the value 22 in the someName field.

Further there are special attributes:

[kbmMW_ConditionalType(...)]

[kbmMW_Dataset(..)] [kbmMW_DatasetRow(..)] [kbmMW_DatasetField(..)] [kbmMW_DatasetVersion(..)] [kbmMW_DatasetDefinition(..)] [kbmMW_DatasetData(..)]

Controls (in combination with [kbmMW_Root]l) serialization and deserialization of colletions containing different types of child objects within the same collection.[kbmMW_Dataset(..)] Controls serialization/deserialization of fields/properties that are of type TkbmCustomMemTable or descendants.

46

Issue Nr 3 2015 BLAISE PASCAL MAGAZINE

GENERATE DELPHI SUPPORT FOR READING AND WRITING XML FILES PAGE 5 - END

Finally it's possible to register custom serialization/deserialization code for handling special serialization/deserialization requirements. It already comes with such for handling kbmMWNullable types, TkbmMWDateTime types, TStream types/descendants and TkbmCustomMemtable descendants. I hope this has given an appetizer for how versatile the kbmMW object serialization/deserialization framework is.

As an example of a fairly complex XSD that kbmMW effortless converts and serializes/deserializes accordingly to, but that even Delphi XE8 fails converting, is the Personal Health Record XSD found here: Schemas/2006-04/PHRModel/R4L_PHRModel.xsd

As kbmMW is a modular framework, one can choose only to use its XML capabilities, its JSON capabilities, its serialization capabilities, its application server capabilities, its database capabilities, its stream storage capabilities, its memory table or its async messaging capabilities etc without having to use all other parts of the kbmMW framework.

But obviously, you will get the best of the best if you take the plunge and choose to take advantage of all the kbmMW features you need in your applications as all parts are designed to work in perfect harmony with each other.

/Kim Madsen / C4D

There is extra code you can download from your subscription site....

You can find sample data here: lHealthRecords/SamplePHRs.aspx

30,00 including VAT 39 including the printed book, ebook and shipping

Quick answers to common problems

Delphi Cookbook

50 hands-on recipes to master the power of Delphi for cross-platform and mobile development on Windows, Mac OS X, Android, and iOS

Daniele Teti

DITO

MAZING

See our special offer: if you take out a subscription for two years the book will cost you only 10,00

RS

CHOICE BLAISE

A

PASCAL

MAGAZINE

E



Issue Nr 3 2015 BLAISE PASCAL MAGAZINE

47

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download