Author: Daniel Wischnewski
How to create a simple XML File viewer, without worrying about the XML itself. The
easiest solution is using the Microsoft XML Document Object Model, installed on
every machine that run MS Internet Explorer 4 or higher.
Answer:
In this article I am showing you a simple XML file viewer, that may be extended to
an XML editor with some work. You may enhance the editor by importing icons for the
different node types, etc. That's up to you.
My main idea is to show you how to import type libraries from readily available
components installed on nearly every machine in the modern windows world.
Note: The MS XML DOM is available for free download and redistribution at
msdn.microsoft.comhttp://msdn.microsoft.com
IMPORTING THE MS XML TYPE LIBRARY
Start Delphi and create a new application, I you haven't done so already. In the
Delphi menu go to Project|Import Type Library... A dialog will appear on your
screen, with a list of all installed and registered COM libraries available for
import. Take a moment and scroll through it, you might be surprised.
Somewhere down the list you find Microsoft XML, version 2.0 (Version 2.0). This is
the type library we are going to import. Additionally, you may see Microsoft XML,
v3.0 (Version 3.0). This is a newer and faster version from MS, we are going to use
the older version however, since it is more common.
After selecting the MS XML, version 2.0 component object, select a Unit Directory,
and press the Create Unit button. The Install button will install the component in
your Component Pallete, additionally.
PREPARING YOUR APPLICATION FORM
Drop a MainMenu (Standard) component on your form, and insert a Open Menu item
(name: Open1).
Drop a TreeView (Win32) component on your form, set Align=alLeft and ReadOnly=True
(name: trvStructure).
Drop an OpenDialog (Dialogs) component on your form (name: OpenDialog1).
Drop a Panel (Standard) component on your form, set Align=alClient and clear the
Caption (name: Panel1).
Drop a StringGrid (Additional) component on the Panel1 set Align=alTop, RowCount=2,
ColCount=2, FixedCols=0, FixedRows=1 (name: grdAttributes).
Drop a Memo (Standard) on the Panel1 set Align=alClient, ReadOnly=True (name
mmoNodeContent).
Note: The names I have used will appear in the source code again!
A PSEUDO CLASS FOR THE XML INTERFACES
Because mapping of interface via pointers introduces some problems I chose to
create a simple class that contains only on variable holding the reference to the
XML Node interface.
1 type
2 TXMLNodeWrapper = class
3 private
4 FNode: IXMLDOMNode;
5 protected
6 public
7 constructor Create(aNode: IXMLDOMNode);
8 property Node: IXMLDOMNode read FNode;
9 end;
The constructor will save the reference in the FNode variable.
CREATING THE XML DOM OBJECT
Creating an instance of the object is rather simple. Having a variable FDocument of
the type IXMLDOMDocument, defined in the imported MSXML_TLB.
10
11 FDocument := CoDOMDocument.Create;
12
13 //Next you need to set up the component to your needs.
14
15 FDocument.async := False;
16 FDocument.validateOnParse := True;
17 FDocument.preserveWhiteSpace := True;
The first I want to do is inserting an base element into the document. Every XML
document needs at least this base element. I have named it xmlstart.
Note: Be careful, XML is case-sensitive.
18
19 FDocument.appendChild(FDocument.createNode(NODE_ELEMENT, 'xmlstart', ''));
PARSING THE XML DOCUMENT
There are quite many ways of parsing XML. I want to show you two recursive ways,
that are very similar, but have quite different results.
(1) NodeList := Node.childNodes;
Returns all children, inlcude some special node types, such as #text or #comment.
These node types require special care.
(2) NodeList := Node.selectNodes('*');
Returns all standard node types, that can be accessed via XSL (XML Structured
Language). These node types are easy in use.
ACCESSING THE NODE LIST
Accessing any item in a Node List is very easy. The length returns the count of
items in the list (equal to Delphis Count property). The Item array gives access to
every Item of the node list.
20 for I := 0 to Pred(XMLNodeList.length) do
21 ShowMessage(XMLNodeList.item[I].nodeName);
MORE INFORMATION ABOUT THE MS XML DOM
The most important web addresses for the MS XML DOM are:
http://msdn.microsoft.com/xmlhttp://msdn.microsoft.com/xml (all about XML)
http://msdn.microsoft.com/downloads/default.asp?URL=/code/topic.asp?URL=/msdn-files/
028/000/072/topic.xml
http://msdn.microsoft.com/downloads/default.asp?URL=/code/topic.asp?URL=/msdn-files/
028/000/072/topic.xml(Downloads)
THE SOURCE CODE FOR THE XML VIEWER
22 unit uMainForm;
23
24 interface
25
26 uses
27 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
28 MSXML_TLB, ComCtrls, Menus, Grids, ExtCtrls, StdCtrls;
29
30 type
31 TXMLNodeWrapper = class
32 private
33 FNode: IXMLDOMNode;
34 protected
35 public
36 constructor Create(aNode: IXMLDOMNode);
37 property Node: IXMLDOMNode read FNode;
38 end;
39
40 TfrmMain = class(TForm)
41 MainMenu1: TMainMenu;
42 File1: TMenuItem;
43 Open1: TMenuItem;
44 trvStructure: TTreeView;
45 OpenDialog1: TOpenDialog;
46 Panel1: TPanel;
47 grdAttributes: TStringGrid;
48 mmoNodeContent: TMemo;
49 procedure FormCreate(Sender: TObject);
50 procedure Open1Click(Sender: TObject);
51 procedure trvStructureChange(Sender: TObject; Node: TTreeNode);
52 private
53 FDocument: IXMLDOMDocument;
54 FFileName: string;
55 procedure LoadXML;
56 public
57 end;
58
59 var
60 frmMain: TfrmMain;
61
62 implementation
63
64 {$R *.DFM}
65
66 { TXMLNodeWrapper }
67
68 constructor TXMLNodeWrapper.Create(aNode: IXMLDOMNode);
69 begin
70 inherited Create;
71 FNode := aNode;
72 end;
73
74 { TFrmMain }
75
76 procedure TfrmMain.FormCreate(Sender: TObject);
77 begin
78 FDocument := CoDOMDocument.Create;
79 FDocument.async := False;
80 FDocument.validateOnParse := True;
81 FDocument.preserveWhiteSpace := True;
82 FDocument.appendChild(FDocument.createNode(NODE_ELEMENT, 'xmlstart', ''));
83
84 grdAttributes.Cells[0, 0] := 'Attribute name';
85 grdAttributes.Cells[1, 0] := 'Attribute value';
86 end;
87
88 procedure TfrmMain.LoadXML;
89 procedure EnterNode(const XMLNode: IXMLDOMNode; TreeNode: TTreeNode);
90 var
91 I: Integer;
92 XMLNodeList: IXMLDOMNodeList;
93 NewTreeNode: TTreeNode;
94 begin
95 NewTreeNode := trvStructure.Items.AddChild(TreeNode, XMLNode.nodeName);
96 NewTreeNode.Data := TXMLNodeWrapper.Create(XMLNode);
97 // use XMLNode.childNodes to get all nodes (incl. special types)
98 XMLNodeList := XMLNode.selectNodes('*');
99 for I := 0 to Pred(XMLNodeList.length) do
100 EnterNode(XMLNodeList.item[I], NewTreeNode);
101 end;
102 begin
103 for I := 0 to trvStructure.Items.Count - 1 do
104 TXMLNodeWrapper(trvStructure.Items.Item[I].Data).Destroy;
105 trvStructure.Items.BeginUpdate;
106 try
107 trvStructure.Items.Clear;
108 EnterNode(FDocument.documentElement, nil);
109 finally
110 trvStructure.Items.EndUpdate;
111 end;
112 end;
113
114 procedure TfrmMain.Open1Click(Sender: TObject);
115 begin
116 if OpenDialog1.Execute then
117 begin
118 FDocument.load(OpenDialog1.FileName);
119 FFileName := OpenDialog1.FileName;
120 LoadXML;
121 end;
122 end;
123
124 procedure TfrmMain.trvStructureChange(Sender: TObject; Node: TTreeNode);
125 var
126 I: Integer;
127 CurrentNode: IXMLDOMNode;
128 begin
129 CurrentNode := TXMLNodeWrapper(Node.Data).Node;
130 Caption := CurrentNode.nodeName;
131 if CurrentNode.selectNodes('*').length = 0 then
132 mmoNodeContent.Text := CurrentNode.text
133 else
134 mmoNodeContent.Text := '';
135 if CurrentNode.attributes.length > 0 then
136 begin
137 grdAttributes.RowCount := Succ(CurrentNode.attributes.length);
138 grdAttributes.FixedRows := 1;
139 for I := 0 to Pred(CurrentNode.attributes.length) do
140 begin
141 grdAttributes.Cells[0, Succ(I)] := CurrentNode.attributes.item[I].nodeName;
142 grdAttributes.Cells[1, Succ(I)] := CurrentNode.attributes.item[I].text;
143 end;
144 end
145 else
146 begin
147 grdAttributes.RowCount := 2;
148 grdAttributes.Cells[0, 1] := '';
149 grdAttributes.Cells[1, 1] := '';
150 end;
151 end;
152
153 end.
|