16

I want to read some nodes of a XML file and show their values in some custom input fields. User can then change the values if needed, and by clicking the Next button these values should be saved back to the XML.

How to do this in Inno Setup script ?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Sunil Sharma
  • 782
  • 1
  • 10
  • 22
  • Related question: [Inno Setup modify XML file based on custom input](http://stackoverflow.com/q/8141886/588306). – Deanna Jun 29 '12 at 11:46

1 Answers1

35

Use the CreateOleObject function to instantiate the standard MSXML2.DOMDocument COM object. The following script shows how to load and save a text value for a single node from the XML file posted below (the script itself was inspired by the examples from MSDN):

[Code]
var
  CustomEdit: TEdit;
  CustomPageID: Integer;

function LoadValueFromXML(const AFileName, APath: string): string;
var
  XMLNode: Variant;
  XMLDocument: Variant;  
begin
  Result := '';
  XMLDocument := CreateOleObject('Msxml2.DOMDocument.6.0');
  try
    XMLDocument.async := False;
    XMLDocument.load(AFileName);
    if (XMLDocument.parseError.errorCode <> 0) then
      MsgBox('The XML file could not be parsed. ' + 
        XMLDocument.parseError.reason, mbError, MB_OK)
    else
    begin
      XMLDocument.setProperty('SelectionLanguage', 'XPath');
      XMLNode := XMLDocument.selectSingleNode(APath);
      Result := XMLNode.text;
    end;
  except
    MsgBox('An error occured!' + #13#10 + GetExceptionMessage, mbError, MB_OK);
  end;
end;

procedure SaveValueToXML(const AFileName, APath, AValue: string);
var
  XMLNode: Variant;
  XMLDocument: Variant;  
begin
  XMLDocument := CreateOleObject('Msxml2.DOMDocument.6.0');
  try
    XMLDocument.async := False;
    XMLDocument.load(AFileName);
    if (XMLDocument.parseError.errorCode <> 0) then
      MsgBox('The XML file could not be parsed. ' + 
        XMLDocument.parseError.reason, mbError, MB_OK)
    else
    begin
      XMLDocument.setProperty('SelectionLanguage', 'XPath');
      XMLNode := XMLDocument.selectSingleNode(APath);
      XMLNode.text := AValue;
      XMLDocument.save(AFileName);
    end;
  except
    MsgBox('An error occured!' + #13#10 + GetExceptionMessage, mbError, MB_OK);
  end;
end;

procedure InitializeWizard;
var  
  CustomPage: TWizardPage;
begin
  CustomPage := CreateCustomPage(wpWelcome, 'Custom Page', 
    'Enter the new value that will be saved into the XML file');
  CustomPageID := CustomPage.ID;
  CustomEdit := TEdit.Create(WizardForm);
  CustomEdit.Parent := CustomPage.Surface;
end;

procedure CurPageChanged(CurPageID: Integer);
begin
  if CurPageID = CustomPageID then
    CustomEdit.Text := LoadValueFromXML('C:\Setup.xml', '//Setup/FirstNode');
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
  Result := True;
  if CurPageID = CustomPageID then
    SaveValueToXML('C:\Setup.xml', '//Setup/FirstNode', CustomEdit.Text);
end;

Here is the XML file used in the script:

<?xml version="1.0" encoding="UTF-8"?>
<Setup>
    <FirstNode>First node value!</FirstNode>
    <SecondNode>Second node value!</SecondNode>
</Setup>
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
TLama
  • 75,147
  • 17
  • 214
  • 392
  • P.S. it would be good to wrap each OLE object function call in this script with the [`OleCheck`](http://www.jrsoftware.org/ishelp/topic_isxfunc_olecheck.htm) which will raise the exception (earlier) when the function call fails (when the result will be different from the `S_OK` value). – TLama Jun 28 '12 at 23:42
  • 2
    The sample code may fail on Windows XP where MSXML 6.0 isn't available. Instead you should use version 3.0: [...] CreateOleObject('Msxml2.DOMDocument.3.0'); – Daniel Lemke Oct 09 '13 at 10:38
  • @Daniel, good point! However, just `Msxml2.DOMDocument` should be enough (system should decide the version to use). – TLama Oct 09 '13 at 10:52
  • Thanks for the example code. Should it be updated to cater for silent installs and logging? Which is the right place in the script to edit the file after install? – Andrew Truckle Sep 16 '21 at 08:08