From MSI to WiX, Part 25 - Installable Items - Updating XML files using XmlFile
To use XmlFile element we need to:
- Add reference to WixUtilExtension extension.
- Add util namespace to <Wix> element:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi"
xmlns:util = "https://schemas.microsoft.com/wix/UtilExtension" >
Here is what we can do with existing XML file using XmlFile element:
- Set the value of an attribute
- Set the text value of an element
- Create new element
- Create new attribute
- Delete the text value of an element
- Delete the attribute
Preparing an installation
Here is the original content of XML file we are going to update (app.config):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<UserName></UserName>
<Parameters>-DeleteAll</Parameters>
<EmptyElement>123</EmptyElement>
<appSettings>
<add key="NoValue" value="" />
<add key="NoValue2" value="" />
<add key="ExtraAttribute" value="MyValue" extra="" />
</appSettings>
<BulkSet1>
<add key="key1" value="" />
<add key="key2" value="" />
<add key="key3" value="" />
</BulkSet1>
<BulkSet2>
<add key="key1" value="" />
<add key="key2" value="" />
<add key="key3" value="" />
</BulkSet2>
</configuration>
This is the wxs file to install app.config file:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi"
xmlns:util="https://schemas.microsoft.com/wix/UtilExtension">
<Product Id="78c586b0-3f59-405f-9f2e-a0370b7be99b"
Name="XmlFileUpdate"
Language="1033"
Version="1.0.0.0"
Manufacturer="XmlFileUpdate"
UpgradeCode="1f711338-7bcc-4cc3-bcd9-1a47bf128409">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLLOCATION" Name="XmlFileUpdate">
<Component Id="ProductComponent"
Guid="03ade8d5-cdab-4a50-a950-e16cebb8bbae">
<File Id="AppConfig"
DiskId="1"
Name="app.config"
Source="app.config"
Vital="yes"
KeyPath="yes" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="ProductFeature" Title="XmlFileUpdate" Level="1">
<ComponentRef Id="ProductComponent" />
</Feature>
</Product>
</Wix>
Set attribute or element value
Now, let's set the value of "NoValue" element (<add> element with key attrubute set to "NoValue) to the value of INSTALLLOCATION property. In other words, from this:
<add key="NoValue" value="" />
we want to get this result:
<add key="NoValue" value="C:\Program Files\XmlFileUpdate\"/>
All we need to do is to add to component XmlFile element:
<Component Id="ProductComponent"
Guid="03ade8d5-cdab-4a50-a950-e16cebb8bbae">
<File Id="AppConfig"
DiskId="1"
Name="app.config"
Source="app.config"
Vital="yes"
KeyPath="yes" />
<util:XmlFile Id="SetKey1"
Action="setValue"
ElementPath="//appSettings/add[\[]@key='NoValue'[\]]/@value"
Value="[INSTALLLOCATION]"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="1" />
</Component>
The following attributes need to be set:
- Action attribute is set to setValue.
- ElementPath attribute contains an XPath or XSLTPattern expression pointing to attribute which value we want to set.
- Value attribute contains new formatted value of the attribute.
- File attribute points to a file where changes will be made. This value is also formatted and that is why we can use [#FileId] notation instead of providing full path to XML file.
- Sequence attribute defines the order in which modification will be made. This value matters only when we need to create new element with attribute. In this case we need to ensure that element is created before attempting to create an attribute. As a good practice, always set this value in order in which you prefer items to be updated.
Alternative version will be to use XPath expression, pointing to an element and use Name attribute to set which attribute's value to change:
<util:XmlFile Id="SetKey2"
Action="setValue"
ElementPath="//appSettings/add[\[]@key='NoValue2'[\]]"
Value="[INSTALLLOCATION]"
Name="value"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="2" />
To set the value of existing attribute to an empty string we need to just omit the Value attribute:
<util:XmlFile Id="SetKey3"
Action="setValue"
ElementPath="//appSettings/add[\[]@key='ExtraAttribute'[\]]"
Name="value"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="3" />
Tip: To target an element, provide XPath (or XSLPattern) expression pointing to an element and do not specify Name attribute. To target an attribute - either provide XPath expression pointing to element and set the name of an attribute in the Name attribute, or provide XPath expression pointing to attribute and do not specify Name attribute.
Based on the tip above, here is how we set the text value of an element:
<util:XmlFile Id="SetKey4"
Action="setValue"
ElementPath="//UserName"
Value="[%USERNAME]"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="4" />
And this is how to set element's text value to empty string:
<util:XmlFile Id="SetKey5"
Action="setValue"
ElementPath="//Parameters"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="5" />
Delete attribute or element' text value
Here is how we can delete an attribute:
<util:XmlFile Id="DeleteKey6"
Action="deleteValue"
ElementPath="//appSettings/add[\[]@key='ExtraAttribute'[\]]"
Name="extra"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="6" />
Here Action attribute is set to deleteValue. The meaning of all other attributes is the same as in previous examples. ElementPath attribute points to a node and Name attribute contains the name of the attribibute to be deleted.
There is inconsistency in the way how XmlFile element works if we will omit the Name attribute. Instead of removing element it removes text value of the element, just like Sequence="5" in example above. So, here is how to remove text value of an element:
<util:XmlFile Id="DeleteKey7"
Action="deleteValue"
ElementPath="//EmptyElement"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="7" />
Create element and attribute
To create a new element, we need to set Action attribute to createElement:
<util:XmlFile Id="CreateElement1"
Action="createElement"
ElementPath="//configuration"
Name="NewElement1"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="8" />
To create a new element and set its text value we need to add Value attribute:
<util:XmlFile Id="CreateElement2"
Action="createElement"
ElementPath="//configuration"
Name="NewElement2"
Value="New Value"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="9" />
Creating element with attributes is little bit more complicated. First, we need to create an element and then create attributes. That is where the value of Sequence attribute is very important. Let's create new add element in appSettings section:
<util:XmlFile Id="CreateElement3"
Action="createElement"
ElementPath="//appSettings"
Name="add"
File="[#AppConfig]"
Sequence="10" />
<util:XmlFile Id="CreateAttribute1"
Action="setValue"
ElementPath="//appSettings/add[\[]not(@key)[\]]"
Name="key"
Value="NewParameter"
File="[#AppConfig]"
Sequence="11" />
<util:XmlFile Id="CreateAttribute2"
Action="setValue"
ElementPath="//appSettings/add[\[]@key='NewParameter'[\]]"
Name="value"
Value="NewValue"
File="[#AppConfig]"
Sequence="12" />
First, we create a new add element (Sequence 10). Second, we create a key attribute. XPath expression is searching for an add element which does not have a key attribute (Sequence 11). Last XmlFile element creates a value attribute (Sequence 12).
Bulk set
XmlFile element supports bulk update.
For example, from this:
<BulkSet1>
<add key="key1" value=""/>
<add key="key2" value=""/>
<add key="key3" value=""/>
</BulkSet1>
we want to get this:
<BulkSet1>
<add key="key1" value="C:\Program Files\XmlFileUpdate\"/>
<add key="key2" value="C:\Program Files\XmlFileUpdate\"/>
<add key="key3" value="C:\Program Files\XmlFileUpdate\"/>
</BulkSet1>
Basically, we want to set every value attribute to the value of INSTALLLOCATION property. Using regular setValue as a value for Action attribute:
<util:XmlFile Id="BulkSetKey1"
Action="setValue"
ElementPath="//configuration/BulkSet1/add"
Name="value"
Value="[INSTALLLOCATION]"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="13" />
creates the following result:
<BulkSet1>
<add key="key1" value="C:\Program Files\XmlFileUpdate\"/>
<add key="key2" value=""/>
<add key="key3" value=""/>
</BulkSet1>
To fix this, we need to set Action attribute to bulkSetValue:
<util:XmlFile Id="BulkSetKey2"
Action="bulkSetValue"
ElementPath="//configuration/BulkSet2/add"
Name="value"
Value="[INSTALLLOCATION]"
File="[#AppConfig]"
SelectionLanguage="XPath"
Sequence="14" />
Here is the result:
<BulkSet2>
<add key="key1" value="C:\Program Files\XmlFileUpdate\"/>
<add key="key2" value="C:\Program Files\XmlFileUpdate\"/>
<add key="key3" value="C:\Program Files\XmlFileUpdate\"/>
</BulkSet2>
This is pretty much all we can do with XmlFile element. Source code for post is in attachment.
Comments
Anonymous
June 08, 2009
> Here is what we can do with existing XML file using XmlFile element: > > * Set the value of an attribute > * Set the text value of an element > * Create new element > * Create new attribute > * Delete the text value of an element > * Delete the attribute And how can I read a text value from element?Anonymous
November 16, 2009
how to got custom config data from UserInterface dialog?Anonymous
January 26, 2011
Is it possible to merge a value for example if the existing value is "test" could I change it to "test,test2" ?Anonymous
June 18, 2012
Thank you, Alex. This post helped me alot! :)Anonymous
June 04, 2013
how to set the value for books book name="value"; book name="value"; book name="value" booksAnonymous
December 11, 2013
Hi, All !! I have successfully created setup for MVC Web Application using wix toolset, it is working fine under Default Web Site. I have no issue under Default Web Site, but can any one help me if i want to create new website with some other port no rather than creating website under Default website in IIS.. i.e.: IIS>> Sites>> Default Web site >>My MVC App is working fine. Problem in below structure:: i.e.: IIS>> Sites>> My MVC App Thanks in Advance!!Anonymous
February 13, 2014
Thanks a lot!!Anonymous
May 13, 2014
Excuse a newbie question here, but with the ElementPath where can I get more information on what is actually suppose to be written there/acceptable correct values? I am an install developer using WiX 3.7 and was given the task of updating a .config file during install. They want 2 entries added - one a ServiceInfo with value of Server Address and one entry ClientMode that can be one of 3 optional values. This was all the information I was given and therefore I do not know what ElementPath should be or the acceptable values that I need to set it to. So can I get more information on ElementPath? Thanks for any help.Anonymous
May 13, 2014
Newbie question here, but how do you determine what the ElementPath should be for any given entry? Have never used this functionality before and have just been given the task of adding 2 entries to an application .config file and only information given was for key ServerInfo = [SERVER_ADDRESS] and key ClientMode=[CLIENT_MODE].
So would like to figure out how to get this ElementPath so that I can get it working. Thanks for Any help.