How to update attributes in an XML file with InstallScript

Nick Knowlson picture Nick Knowlson · Nov 9, 2010 · Viewed 8.3k times · Source

Question:

I am struggling trying to figure out how to update some attributes in an XML file using InstallScript. I would like to use proper XML parsing functions, but I can't find anything that suggests this version of InstallScript is capable of it. How can I do this? Should I just attempt falling back on a combination of FileInsertLine and FileGrep? Is there a library I'm missing?

Background:

What software versions?
I am using InstallShield 11 on Windows Server 2003 R2.

Why am I not just using the existing 'XML File Changes' feature?
Because I am doing an upgrade and running into this bug. It affects the XML File Change feature because it is tied to a Component (well, that's my guess). I spent too long trying the official workaround, but couldn't coax it to work. I eventually found out it was much easier and more reliable to copy the files over using InstallScript + a single line batch file. It feels a bit hacky, but it is something that actually works.

Now I am trying to figure out the easiest and simplest-to-figure-out-years-later way to replicate the effects of the 'XML File Changes' feature in InstallScript.

Please let me know if you need any more information, I will be glad to provide it.

EDIT:

I ended up going with the InstallScript way to do it after all - it has tended to be the way that everything else in this installer project was implemented, and it looked (and turned out to be) pretty quick to do. I started out with the code shown by TheTraveler in that thread and modified it to suit my needs.

Here is the code:

prototype UpdateWebConfigAttributes();  
prototype ReplaceValueOf(OBJECT, STRING, STRING);   

function UpdateWebConfigAttributes()
    OBJECT oDoc, oNode;
    NUMBER i;                  
    STRING sWebConfigFilePath;   
    BOOL successfulLoad;
begin   

    sWebConfigFilePath = "Path\\To\\Web.config";  

    if Is(FILE_EXISTS, sWebConfigFilePath) = FALSE then
        MessageBox("Could not find Web.config file.", 0);
    endif;

    // get values from public properties
    set oDoc = CreateObject("Msxml2.DOMDocument.4.0");  
    if !IsObject(oDoc) then
        MessageBox("Could not create XML Document", 0);
        return -1;     
    endif;     

    oDoc.async = FALSE;  
    oDoc.setProperty("SelectionLanguage", "XPath");

    successfulLoad = oDoc.load(sWebConfigFilePath);
    if !successfulLoad then
        MessageBox("Could not load Web.config as an xml file", SEVERE);                         
        return -1;
    endif;

    ReplaceValueOf(oDoc, "//add[@key=\"ConnectionDriver\"]", CONNECT_DRIVER);
    ReplaceValueOf(oDoc, "//add[@key=\"ConnectionType\"]", CONNECT_TYPE);
    ReplaceValueOf(oDoc, "//add[@key=\"ConnectionString\"]", CONNECT_STRING_WEBCONFIG);
    ReplaceValueOf(oDoc, "//add[@key=\"ShowConnection\"]", "False");

    oDoc.save(sWebConfigFilePath);
    set oDoc = NOTHING;
end;   


function ReplaceValueOf(oDoc, xPath, valueToPutIn)
    OBJECT oNode;
begin
    set oNode = oDoc.selectNodes(xPath)(0);
    try
        oNode.attributes.getNamedItem("value").value = valueToPutIn;
    catch 
        MessageBox("Could not set '" + xPath + "' with '" + valueToPutIn + "'", SEVERE);
    endcatch;  
end;    

Answer

Christopher Painter picture Christopher Painter · Nov 9, 2010

I recall the XML Changes being pretty buggy back in those days. What project type are you using? If it's an MSI type then I would create a merge module in WiX and use it's XML changes pattern. You can then add that merge module to your InstallShield project.

If you really do want to do it in InstallScript then you are going to have to use CoCreateObject() to call into an XML DOM.

There is a discussino and example over at XML Installscript

But again, I wouldn't do it this way. I'd either upgrade to a newer version of InstallShield or I'd leverage the Util extension in WiX to keep it declarative. I don't like writing these types of custom actions as it usually doesn't end well.

Util Schema