How to Exclude Files Using XSLT in Wix Installer

XSLT is used to transform data from one XML to another desired XML using XPath queries.

The wix heatdirectory task has an optional parameter ‘Transforms’, where XSLT can be used to define file filtering to be used.

Create a XSLT file with defined filtering

In this example, I’ve created an XSLT file ‘exdir.xslt’ excluding files from a folder \Tests\

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
>
  
  <xsl:template match="@*|*">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="*" />
    </xsl:copy>
  </xsl:template>

  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

  <xsl:key name="excludefiles-search" match="wix:Component[contains(wix:File/@Source, '\Tests\') 
]" use="@Id" />
 
  <xsl:template match="wix:Component[key('excludefiles-search', @Id)]" />
  <xsl:template match="wix:ComponentRef[key('excludefiles-search', @Id)]" />
  
</xsl:stylesheet>

Add the xslt to heatdirectory task of wix project

Refer to other articles on How to add all files from a folder to MSI Installer using WIX.

For the same project from the referred article, the transforms parameter has been replaced with ‘exdir.xslt’.

Before building the project, the xslt file should be copied to the wix project folder.

 <Target Name="BeforeBuild">
    <PropertyGroup>
           <DefineConstants>ONEDIRPATH=..\OneDir</DefineConstants>
    </PropertyGroup>
    <HeatDirectory Directory="..\OneDir" 
                   DirectoryRefId="INSTALLFOLDER" 
                   OutputFile="onedir.wxs" 
                   ComponentGroupName="OneDirComponentGroup" 
                   PreprocessorVariable="var.ONEDIRPATH" 
                   ToolPath="$(WixToolPath)" 
                   AutogenerateGuids="true" 
                   Transforms="exdir.xslt" 
                   SuppressRootDirectory="true" 
                   SuppressRegistry="true" />
</Target>

Before using Transforms xslt

Without the optional parameter ‘Transforms’, the heat directory task produced a file list containing all files from \Tests folder.

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Directory Id="dir16EC451543B18B3AEC00A3B1E1A310EF" Name="Tests" />
        </DirectoryRef>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="OneDirComponentGroup">
            <Component Id="cmpF22D40156F8E16FBFA89C752FF9D0EF9" Directory="INSTALLFOLDER" Guid="*">
                <File Id="fil2DACDED111D2125FD9BAF52808E5CEB0" KeyPath="yes" Source="$(var.ONEDIRPATH)\api-ms-win-core-console-l1-1-0.dll" />
            </Component>
            <Component Id="cmpD571DFC958168320FBD2D9FC886F151C" Directory="INSTALLFOLDER" Guid="*">
                <File Id="fil17B6D4224AEC1885E80DC07CC51923FB" KeyPath="yes" Source="$(var.ONEDIRPATH)\api-ms-win-core-console-l1-2-0.dll" />
            </Component>
            <Component Id="cmpD8A1B6F27CFA30B3B8ED0F2E39347900" Directory="dir16EC451543B18B3AEC00A3B1E1A310EF" Guid="*">
                <File Id="filCACCC9F5FE06314F37618DD8A0F77AED" KeyPath="yes" Source="$(var.ONEDIRPATH)\Tests\api-ms-win-core-console-test1.dll" />
            </Component>
            <Component Id="cmpFDB03ECC52179924EFAF4A8968586532" Directory="dir16EC451543B18B3AEC00A3B1E1A310EF" Guid="*">
                <File Id="fil012AB0CD265F88F998DAC28B2527ED11" KeyPath="yes" Source="$(var.ONEDIRPATH)\Tests\api-ms-win-core-console-test2.dll" />
            </Component>
        </ComponentGroup>
    </Fragment>
</Wix>

After using the Transforms xslt

With the newly defined HeatDirectory, Wix showed a file list without files from the \Tests folder as desired.

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Directory Id="dir16EC451543B18B3AEC00A3B1E1A310EF" Name="Tests" />
        </DirectoryRef>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="OneDirComponentGroup">
            <Component Id="cmpF22D40156F8E16FBFA89C752FF9D0EF9" Directory="INSTALLFOLDER" Guid="*">
                <File Id="fil2DACDED111D2125FD9BAF52808E5CEB0" KeyPath="yes" Source="$(var.ONEDIRPATH)\api-ms-win-core-console-l1-1-0.dll" />
            </Component>
            <Component Id="cmpD571DFC958168320FBD2D9FC886F151C" Directory="INSTALLFOLDER" Guid="*">
                <File Id="fil17B6D4224AEC1885E80DC07CC51923FB" KeyPath="yes" Source="$(var.ONEDIRPATH)\api-ms-win-core-console-l1-2-0.dll" />
            </Component>
        </ComponentGroup>
    </Fragment>
</Wix>

Run:

The heatdirectory task triggered heat.exe, and -t exdir.xslt showed the transforms parameter.

Leave a Comment