Search code examples
xmlxpathinno-setupcdatapascalscript

How to save CDATA value with Inno Setup into XML file?


I need to save a CDATA value into an XML file through Inno Setup.

I search into the Msxml2.DOMDocument.6.0 document but without success regarding the way to write properly the value into the node.

If I try just to declare XMLNode.Text := AValue; with the value I want ExpandConstant('<string><![CDATA[my value]]></string>); in my code, the XML interpreter replace all the characters '<>' with the XML entities &lt; and &gt;.

function SaveValueToXML(const AFileName, APath, AValue : 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');
      XMLDocument.setProperty(
        'SelectionNamespaces', 'xmlns:ns=''urn:mathworks.matlab.settings''');
      XMLNode := XMLDocument.selectSingleNode(APath);
      XMLNode.Text := AValue;
      XMLDocument.save(AFileName);      
    end;
  except
    MsgBox('An error occured!' + #13#10 + GetExceptionMessage, mbError, MB_OK);
  end;
end;

function NextButtonClick(PageID: Integer): Boolean;
var
  XMLFile: string;
begin
  Result := True;
  if (PageId = wpReady) then 
  begin
    XMLFile := ExpandConstant('path to xml file');
    if FileExists(XMLFile) then 
    begin
      SaveValueToXML(
        XMLFile, '//ns:key[@name=''InstallationFolder'']',
        ExpandConstant('&lt;![CDATA[value to write]]&gt;&lt;/string&gt;'));      
    end;
  end;
end; 

Is there a way to declare CDATA section with Msxml2.DOMDocument.6.0 with Inno Setup? I tried with the escaped character and it produced the same result also with the XMLNode := XMLNode.createCDATASection(Avalue); syntax without success...

XML file contains:

<?xml version="1.0" encoding="UTF-8"?>
<settings name="matlab" visible="true" xmlns="urn:mathworks.matlab.settings" xsi:schemaLocation="urn:mathworks.matlab.settings settings.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <!-- ... -->
    <settings name="addons">
        <!-- ... -->
        <key name="InstallationFolder">
            <string></string>
        </key>
    </settings>
</settings>

And we need the code to modify XML to:

<?xml version="1.0" encoding="UTF-8"?>
<settings name="matlab" visible="true" xmlns="urn:mathworks.matlab.settings" xsi:schemaLocation="urn:mathworks.matlab.settings settings.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <!-- ... -->
    <settings name="addons">
        <!-- ... -->
        <key name="InstallationFolder">
            <string>
                <value><![CDATA[my value]]></value>
            </string>
        </key>
    </settings>
</settings>

final code :

const
  NODE_ELEMENT = 1; 

(*Function to load and save value to an XML file*)
function SaveValueToXML(const AFileName, APath, AValue : string): string;
var
  XMLNode: Variant;
  XMLNode2: 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');
      XMLDocument.setProperty('SelectionNamespaces', 'xmlns:ns=''urn:mathworks.matlab.settings''');
      XMLNode := XMLDocument.selectSingleNode(APath);
      XMLNode2 := XMLDocument.createNode(NODE_ELEMENT, 'value', 'urn:mathworks.matlab.settings');
      XMLNode2.appendChild(XMLDocument.createCDATASection(AValue));
      XMLNode.appendChild(XMLNode2);      
      XMLDocument.save(AFileName);     
    end;
  except
    MsgBox('An error occured!' + #13#10 + GetExceptionMessage, mbError, MB_OK);
  end;
end;

function NextButtonClick(PageID: Integer): Boolean;
var
  XMLFile: string;
begin
  Result := True;
  if (PageId = wpReady) then 
  begin
    XMLFile := ExpandConstant('{userappdata}\MathWorks\MATLAB\R2018b\matlab.settings');
    if FileExists(XMLFile) then 
    begin
      SaveValueToXML(XMLFile, '//ns:key[@name=''InstallationFolder'']/ns:string', ExpandConstant('{userappdata}\MathWorks\MATLAB Add-Ons'));      
    end;
  end;
end; 

Solution

  • createCDATASection is a method of a "document", not a "node".

    This works for me:

    XMLNode.appendChild(XMLDocument.createCDATASection(AValue));
    

    Whole code, including creation of the value node:

    const
      NODE_ELEMENT = 1;
    
    XMLNode2 := XMLDocument.createNode(NODE_ELEMENT, 'value', 'urn:mathworks.matlab.settings');
    XMLNode2.appendChild(XMLDocument.createCDATASection('my value'));
    XMLNode.appendChild(XMLNode2); 
    

    Additionally, your XPath needs to select the inner string node:

    //ns:key[@name='InstallationFolder']/ns:string
    

    Result:

    <key name="InstallationFolder">
        <string>
            <value><![CDATA[my value]]></value></string>
    </key>