Let's have a look at the following steps:
- Create a new VCL application and drop three TButton and a TMemo. Align all the buttons as a toolbar at the top of the form and the memo on the remaining form client area.
- From left to right, name the buttons btnGenerateXML, btnModifyXML, btnParseXML, and btnTransformXML.
- The real work on the XML will be done by the TXMLDocument component. So, drop one instance of the form and set its DOMVendor property to Omni XML.
- We will use static data as our data source. A simple matrix is enough for this recipe. Just after the implementation section of the unit, write the code that follows:
type
TCarInfo = (
Manufacturer = 1,
Name = 2,
Currency = 3,
Price = 4);
var
Cars: array [1 .. 4] of
array [Manufacturer .. Price] of string = (
(
'Ferrari','360 Modena','EUR', '250,000'
),
(
'Ford', 'Mustang', 'USD', '80,000'
),
(
'Lamborghini', 'Countach', 'EUR','300,000'
),
(
'Chevrolet', 'Corvette', 'USD', '100,000'
)
);
- We will use a TMemo to display the XML and the data. To keep things clear, create a public property called Xml on the form and map its setter and getter to the Memo1.Lines.Text property. Use the following code:
//...other form methods declaration
private
procedure SetXML(const Value: String);
function GetXML: String;
public
property Xml: String read GetXML write SetXML;
end;
//...then in the implementation section
function TMainForm.GetXML: String;
begin
Result := Memo1.Lines.Text;
end;
procedure TMainForm.SetXML(const Value: String);
begin
Memo1.Lines.Text := Value;
end;
- Now, create event handlers for each button. For btnGenerateXML, write the following code:
procedure TMainForm.btnGenerateXMLClick(Sender: TObject);
var
RootNode, Car, CarPrice: IXMLNode;
i: Integer;
s: String;
begin
XMLDocument1.Active := True;
try
XMLDocument1.Version := '1.0';
RootNode := XMLDocument1.AddChild('cars');
for i := Low(Cars) to High(Cars) do
begin
Car := XMLDocument1.CreateNode('car');
Car.AddChild('manufacturer').Text :=
Cars[i][TCarInfo.Manufacturer];
Car.AddChild('name').Text :=
Cars[i][TCarInfo.Name];
CarPrice := Car.AddChild('price');
CarPrice.Attributes['currency'] :=
Cars[i][TCarInfo.Currency];
CarPrice.Text := Cars[i][TCarInfo.Price];
RootNode.ChildNodes.Add(Car);
end;
XMLDocument1.SaveToXML(s);
Xml := s;
finally
XMLDocument1.Active := False;
end;
end;
- Now, we have to write the code to change the XML. In the btnModifyXML click event handler, write the following code:
procedure TMainForm.btnModifyXMLClick(Sender: TObject);
var
Car, CarPrice: IXMLNode;
s: string;
begin
XMLDocument1.LoadFromXML(Xml);
try
Xml := '';
Car := XMLDocument1.CreateNode('car');
Car.AddChild('manufacturer').Text := 'Hennessey';
Car.AddChild('name').Text := 'Venom GT';
CarPrice := Car.AddChild('price');
CarPrice.Attributes['currency'] := 'USD';
CarPrice.Text := '600,000';
XMLDocument1.DocumentElement.ChildNodes.Add(Car);
XMLDocument1.SaveToXML(s);
Xml := s;
finally
XMLDocument1.Active := False;
end;
end;
- Write the following code under the btnParseXML click event handler:
procedure TMainForm.btnParseXMLClick(Sender: TObject);
var
CarsList: IDOMNodeList;
CurrNode: IDOMNode;
childidx, i: Integer;
CarName, CarManufacturer, CarPrice, CarCurrencyType:
string;
begin
XMLDocument1.LoadFromXML(Xml);
try
Xml := '';
CarsList := XMLDocument1.
DOMDocument.getElementsByTagName('car');
for i := 0 to CarsList.length - 1 do
begin
CarName := ''; CarManufacturer := '';
CarPrice := ''; CarCurrencyType := '';
for childidx := 0 to
CarsList[i].ChildNodes.length - 1 do
begin
CurrNode := CarsList[i].ChildNodes[childidx];
if CurrNode.nodeName.Equals('name') then
CarName := CurrNode.firstChild.nodeValue;
if CurrNode.nodeName.Equals('manufacturer') then
CarManufacturer := CurrNode.firstChild.nodeValue;
if CurrNode.nodeName.Equals('price') then
begin
CarPrice := CurrNode.firstChild.nodeValue;
CarCurrencyType :=
CurrNode.Attributes.
getNamedItem('currency').nodeValue;
end;
end;
Xml := Xml +
'Name = ' + CarName + sLineBreak +
'Manufacturer = ' + CarManufacturer + sLineBreak +
'Price = ' +
CarPrice + CarCurrencyType + sLineBreak +
'-----' + sLineBreak;
end;
finally
XMLDocument1.Active := False;
end;
end;
- Write the following code under the btnTransformXML click event handler:
procedure TMainForm.btnTransformClick(Sender: TObject);
var
LXML, LXSL: string;
LOutput: string;
begin
LXML := TFile.ReadAllText('..\..\..\cars.xml');
LXSL := TFile.ReadAllText('..\..\..\cars.xslt');
LOutput := Transform(LXML, LXSL);
TFile.WriteAllText('..\..\..\cars.html', LOutput);
ShellExecute(0, PChar('open'),
PChar('file:///' +
TPath.GetFullPath('..\..\..\cars.html')), nil,
nil, SW_SHOW);
end;
- Now, add the following function in your form implementation section:
function Transform(XMLData: string; XSLT: string): String;
var
LXML, LXSL: IXMLDocument;
LOutput: WideString;
begin
LXML := LoadXMLData(XMLData);
LXSL := LoadXMLData(XSLT);
LXML.DocumentElement.TransformNode(LXSL.DocumentElement,
LOutput);
Result := String(LOutput);
end;
- Run the application by hitting F9 (or by going to Run | Run).
- Click on the btnGenerateXML button, and you should see some XML data in the memo.
- Click on the btnModifyXML button, and you should see some more XML in the memo.
- Click on btnParseXML, and you should see the same data as before, but with normal text representation.
- After the third click, you should see something similar to the following screenshot:
Figure 1.14: Text representation of the XML data generated and modified
- Now, copy the cars.xml and cars.xslt files from the respective recipe folder to the parent folder of your project folder and click on the btnTransformXML button.
- The system default browser should appear, showing something like the following screenshot:
Fig. 1.15 XML data transformed into HTML using an XSLT transformation