15

I'm new to delphi and now I have to read create an xml. my code is the following:

unit writexml1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, xmldom, XMLIntf, StdCtrls, msxmldom, XMLDoc;

type
  TForm1 = class(TForm)
    XMLDocument1: TXMLDocument;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.SaveClick(Sender: TObject);
var
  rootName: String;
  childNode: String;
  attrChild: string;
  iXml: IDOMDocument;
  iRoot, iNode, iNode2, iChild, iAttribute: IDOMNode;
  XMLDoc: TXMLDocument;
begin
  XMLDoc.Active := False;
  XMLDoc.XML.Text := '';
  XMLDoc.Active := True;
  XMLDoc.SaveToFile('C:\Documents and Settings\a\Desktop\zulfa.xml');
  iXml := XMLDoc.DOMDocument;
  iRoot := iXml.appendChild(iXml.createElement('xml'));
  iNode := iRoot.appendChild(iXml.createElement('test'));
  iNode.appendChild(iXml.createElement('test2'));
  iChild := iNode.appendChild(iXml.createElement('test3'));
  iChild.appendChild(iXml.createElement('Simple calue'));
  iNode.insertBefore(iXml.createElement('test4'), iChild);
  iNode2 := iNode.cloneNode(True);
  iRoot.appendChild(iNode2);
  iAttribute := iXml.createAttribute('color');
  iAttribute.nodeValue := 'red';
  iNode2.attributes.setNamedItem(iAttribute);
end;

end.

The problem is that while clicking the save button it shows the exception ,the exception is

Project writexml1.exe raised exception class EAccessViolation  with message 
'Access violation at address 004391B9 in module writexml.exe
1
  • Not related to your question, but why are you saving the content of XMLDoc to a file before you have any XML in it? Looks like your code will never result in a file with xml in it.
    – Sam M
    Commented Dec 2, 2011 at 21:16

4 Answers 4

43

your code looks a little complicated. I would suggest: forget TXMLDocument and IDOMDOCUMENT, use IXMLDOCUMENT instead (the way to to use it ist almost the same then TXmlDocument but you dont need a component).

This code should demonstrate, how simple it is:

{...}
Var
  XML : IXMLDOCUMENT;
  RootNode, CurNode : IXMLNODE;
begin
  XML := NewXMLDocument;
  XML.Encoding := 'utf-8';
  XML.Options := [doNodeAutoIndent]; // looks better in Editor ;)
  RootNode := XML.AddChild('XML');
  CurNode := RootNode.AddChild('Test');
  CurNode := CurNode.AddChild('Test2');
  CurNode.Text := 'Some Test 2 text';
  CurNode.Attributes['NewAttribute'] := 'Some Test2 Attribute Value';
  XMl.SaveToFile('C:\Documents and Settings\a\Desktop\zulfa.xml');
{...}

This is how the resulting File would look like:

<?xml version="1.0" encoding="utf-8"?>
<XML>
  <Test>
    <Test2 NewAttribute="Some Test2 Attribute Value">Some Test 2 text</Test2>
  </Test>
</XML>

I hope this helps

PS: This sample only needs the Units XMLIntf and XmlDoc so you can tidy your uses a little.

13

You need to create the XMLDoc instance before you can use it:

XMLDoc := TXMLDocument.Create(...);
try
  ... do stuff with XMLDOC
finally
  XMLDoc.Free;
end;
5
  • 9
    Be careful, though. Dynamically creating a TXMLDocument with a nil Owner causes the TXMLDocument to act as an interface instead of an object. Calling Free() on such an instance would be very bad. If you want to use Free(), then you have to provide a non-nil Owner (in which case, the Free() is redundant since the Owner will free the TXMLDocument when the Owner is freed). If you dynamically allocate a TXMLDocument with a nil Owner, you MUST assign it to a IXMLDocument variable, in which case use NewXMLDocument() instead of TXMLDocument.Create(nil). Commented Dec 2, 2011 at 21:22
  • @remy I edit the answer to put in the constructor. But I've no idea what paramters to pass. Hence the .... The original answer was lacking detail. Commented Dec 2, 2011 at 22:31
  • 1
    Like any other component, TXMLDocument's constructor takes a TComponent Owner as input. If you specify a non-nil Owner, the Owner will take ownership of freeing the TXMLDocument. If you specify a nil Owner instead, then TXMLDocument will be ownerless and you are responsible for freeing it. But TXMLDocument is special in that latter case, as it does not act as a normal component when it has a nil Owner, it acts as a reference-counted interface instead, so you have to involve the reference counting system in order to free it properly. Commented Dec 2, 2011 at 23:29
  • @Remy: When I allocate XML document through NewXmlDocument(), how can I free instance when no longer need it? Commented Feb 21, 2013 at 14:11
  • 2
    @truthseeker: NewXmlDocument() returns a reference-counted IXMLDocument interface. It is freed automatically when there are no more references to it. You can let it go out of scope normally, or you can assign nil to it if you want to release it earlier. Commented Feb 21, 2013 at 16:36
13

SaveClick() is declaring a local XMLDoc variable that is not assigning a valid TXMLDocument object before you use i. You have a separate XMLDocument1 component on your TForm but you are not using it. Get rid of XMLDoc and use XMLDocument1 instead.

Also, you are accessing the underlying DOMDocument directly. Use the TXMLDocument's own methods to build up the XML instead, do not drop down to the DOM layer unless you need to access vendor-specific functionality (which you do not in this situation).

Try this:

procedure TForm1.SaveClick(Sender: TObject); 
var 
  iRoot, iNode, iNode2, iChild: IXMLNode; 
begin 
  XMLDocument1.Active := False;
  XMLDocument1.XML.Text := '';    
  XMLDocument1.Active := True;
  iRoot := XMLDocument.AddChild('xml'); 
  iNode := iRoot.AddChild('test'); 
  iNode.AddChild('test2'); 
  iChild := iNode.AddChild('test3'); 
  iChild.Text := 'Simple value'; 
  iNode.AddChild('test4', iNode.ChildNodes.IndexOf(iChild)); 
  iNode2 := iNode.CloneNode(True); 
  iRoot.ChildNodes.Add(iNode2); 
  iNode2.Attributes['color'] := 'red'; 
  XMLDocument1.SaveToFile('C:\Documents and Settings\a\Desktop\zulfa.xml'); 
  XMLDocument1.Active := False;
end; 

That produces the following XML:

<?xml version="1.0" encoding="utf-8"?>
<xml>
  <test>
    <test2 />     
    <test4 />
    <test3>Simple value</test3>
  </test>
  <test color="red">
    <test2 />     
    <test4 />
    <test3>Simple value</test3>
  </test>
</xml>

With that said, using IXMLDocument instead of TXMLDocument, like @knowledgestacker suggested, is usually a better choice.

0

I wrote a library to manage and simplify working with XML files, you can check it here.

Not sure of what structure you wanted to create but here's an example:

uses
  ..., IXMLData;

procedure TForm1.Button3Click(Sender: TObject);
var
  d : TIXMLDoc;
  n1, n2 : IXMLNode;
begin
  d := TIXMLDoc.Create('XML');  //By default it uses utf-8 encoding but you specify other encoding as well
  n1 := d.addNode('Test');
  n2 := d.addNode(n1,'Test2');  //add node Test2 as child of node Test
  n2.Attributes['NewAttribute'] := 'Some Test2 Attribute Value';
  n2.Text := 'Some Test 2 text';
  d.SaveTofile('C:\Documents and Settings\a\Desktop\zulfa.xml');  
end;

It will produce this XML:

<XML>
  <Test>
    <Test2 NewAttribute="Some Test2 Attribute Value">Some Test 2 text</Test2>
  </Test>
</XML>

Not the answer you're looking for? Browse other questions tagged or ask your own question.