Book Image

Delphi Cookbook

By : Daniele Teti
Book Image

Delphi Cookbook

By: Daniele Teti

Overview of this book

Table of Contents (14 chapters)
Delphi Cookbook
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Manipulating and transforming XML documents


XML stands for eXtensible Markup Language (http://en.wikipedia.org/wiki/XML) and is designed to represent, transport, and store hierarchical data in trees of nodes. You can use XML to communicate with different systems to store configuration files, complex entities, and so on. All of these use a standard and powerful format. Delphi has had good support for XML for more than a decade now.

Getting ready

All the basic XML-related activities can be summarized with the following points:

  • Generating XML data

  • Parsing XML data

  • Parsing XML data and modifying it

In this recipe, we will see how to do all these activities.

How to do it…

  1. 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 to the remaining form client area.

  2. From left- to right-hand side, name the buttons as btnGenerateXML, btnModifyXML, and btnParseXML.

  3. 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 ADOM XML v4.

  4. We'll 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 following code:

    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'
                )
              ); 
  5. We will use a TMemo component to display the XML and the data. To keep things clear, create on the form a public property called XML and map its setter and getter methods 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;
    
  6. Now, create event handlers for each button. For the btnGenerateXML button, 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;
    
  7. Now we've 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;
    
  8. 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;
    
  9. Run the application by hitting F9 (or navigate to Run | Run).

  10. Click on the btnGenerateXML button and you should see some XML data in the memo.

  11. Click on the btnModifyXML button and you should see some more XML in the memo.

  12. Click on the last button and you should see the same data as before, but in normal text representation.

  13. After the third click, you should see something like the following screenshot:

    Text representation of the XML data generated and modified

How it works…

  • The first button generates the XML representation of the data in our matrix. We've used some car information as sample data.

    Note

    Note that the prices of the cars are not real.

  • To create an XML, there are three fundamental TXMLDocument methods:

    • XMLNode := XMLDocument1.CreateNode('node');

    • XMLNode.AddChild('childnode');

    • XMLNode.Attributes['attrname'] := 'attrvalue';

  • There are other very useful methods but these are the basics of XML generation.

  • The btnModifyXML button loaded the XML into the memo and appended some other data (another car) to the list. Then, it updated the memo with the new updated XML. The following are the most important lines to note:

    //Create a node without adding it to the DOM
    Car := XMLDocument1.CreateNode('car'); 
    
    //fill Car XMLNode… and finally add it to the DOM 
    //as child of the root node
    XMLDocument1.DocumentElement.ChildNodes.Add(Car);
  • The code under the btnParseXMLClick event handler allows you to read the data in the XML tree as simple text.

There's more...

There are many things to say about XML ecospace. There are XML engines that provide facilities to search data in an XML tree (XPath), validate an XML using another XML (XML Schema or DTD), transform an XML into another kind of format using another XML (XSLT), and for many others uses (http://en.wikipedia.org/wiki/List_of_XML_markup_languages). The good thing is that, just like XML itself, the DOM object is also standardized, so every library that is compliant to the standard has the same methods, from Delphi to JavaScript and from Python to C#.

TXMLDocument allows you to select the DOMVendor implementation. By default, there are three implementations available:

  • MSXML: This is from Microsoft and implemented as a COM object. This supports XML transformations and is available only on Windows (so no Android, iOS, or Mac OS X).

  • ADOM XML: This is an open source Delphi implementation and does not support transformations. This is available on all the supported Delphi platforms, so if you plan to write XML handling code on a mobile or Mac, this is the way to go.

  • XSLT: This allows you to transform an XML into something else, using another XML as a stylesheet. The following function loads an XML and an XSLT from two string variables. Then, use the XSLT document to transform the XML document. The following code shows the details:

    function Transform(XMLData: string; XSLT: string): WideString;
    var
      XML: IXMLDocument;
      XSL: IXMLDocument;
    begin
      XML := LoadXMLData(XMLData);
      XSL := LoadXMLData(XSLT);
      XML.DocumentElement.TransformNode(XSL.DocumentElement, Result)
    end;
    

    This function doesn't know about the output format because it is defined by the XSLT document. The result could be an XML, an HTML, a CSV, or a plain text, or whatever the XSLT defines, the code doesn't change.

    XSLT can be really useful—go to http://www.w3schools.com/xsl/xsl_languages.asp for further details about the language.