Home > Mobile >  Wix Harvest - Flatten Subfolders using XSLT
Wix Harvest - Flatten Subfolders using XSLT

Time:07-01

Assume the following folder structure:

rootfolder
   \_A
      \_myfile.txt
      \_myfile2.txt
   \_myfile.txt
   \_myfile2.txt

So there is a directory named rootfolder which contains myfile.txt and myfile2.txt and a subfolder named A which contains the same files (with different content).

When I harvest this folder using heat.exe using the following parameters...

"heat.exe" dir ".\rootfolder" -v -cg MyComponent -gg -scom -sreg -sfrag -srd -dr MyDirectoryRef -var var.baseDir -out rootfolder.wxs

The generated rootfolder.wxs is as below (component IDs shortened for readability):

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="MyDirectoryRef">
            <Component Id="cmp1" Guid="{FEAA7D77-6660-4B5A-A854-B701F185D0DE}">
                <File Id="fil81292AD47AFA19A6E288E2D359E41A6F" KeyPath="yes" Source="$(var.baseDir)\myfile.txt" />
            </Component>
            <Component Id="cmp2" Guid="{FEAA7D77-6660-4B5A-A854-B701F185D0DF}">
                <File Id="fil81292AD47AFA19A6E288E2D359E41A6F" KeyPath="yes" Source="$(var.baseDir)\myfile2.txt" />
            </Component>
            <Directory Id="dir1" Name="A">
                <Component Id="cmp3" Guid="{52737913-3452-42D2-99FE-71A60DAA425F}">
                    <File Id="fil4C22841B1246538F82E2807574D642D2" KeyPath="yes" Source="$(var.baseDir)\A\myfile.txt" />
                </Component>
                <Component Id="cmp4" Guid="{52737913-3452-42D2-99FE-71A60DAA426F}">
                    <File Id="fil4C22841B1246538F82E2807574D642D2" KeyPath="yes" Source="$(var.baseDir)\A\myfile2.txt" />
                </Component>
            </Directory>
        </DirectoryRef>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="MyComponent">
            <ComponentRef Id="cmp1" />
            <ComponentRef Id="cmp2" />
            <ComponentRef Id="cmp3" />
            <ComponentRef Id="cmp4" />
        </ComponentGroup>
    </Fragment>
</Wix>

What I want to do is depending on some selection during the installation, copy myfile.txt and myfile2.txt from the subfolder A to the final installation directory referred by MyDirectoryRef or copy directly from rootfolder itself otherwise.

I tried to do so using the following XSLT file:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi">
  <xsl:output method="xml" indent="yes" cdata-section-elements="wix:Condition"/>
  <xsl:strip-space elements="*" />

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="wix:Component">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="wix:Directory[@Name='A']">
    <xsl:copy-of select="node()"/>
  </xsl:template>
  
  <xsl:template match="wix:Component">
    <xsl:variable name="source-path" select="wix:File/@Source"/>
    <xsl:choose>
       <xsl:when test="contains($source-path,'A')">
          <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
            <xsl:element name="Condition" namespace="http://schemas.microsoft.com/wix/2006/wi">
               <xsl:text>SOME_VAR="A"</xsl:text>
            </xsl:element>
          </xsl:copy>
       </xsl:when>
       <xsl:otherwise>
          <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
            <xsl:element name="Condition" namespace="http://schemas.microsoft.com/wix/2006/wi">
               <xsl:text>SOME_VAR="B"</xsl:text>
            </xsl:element>
          </xsl:copy>
       </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

However, the output WXS file I am getting is as below:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="MyDirectoryRef">
            <Component Id="cmp1" Guid="{FEAA7D77-6660-4B5A-A854-B701F185D0DE}">
                <File Id="fil81292AD47AFA19A6E288E2D359E41A6F" KeyPath="yes" Source="$(var.baseDir)\myfile.txt" />
                <Condition>SOME_VAR="B"</Condition>
            </Component>
            <Component Id="cmp2" Guid="{FEAA7D77-6660-4B5A-A854-B701F185D0DF}">
                <File Id="fil81292AD47AFA19A6E288E2D359E41A6F" KeyPath="yes" Source="$(var.baseDir)\myfile2.txt" />
                <Condition>SOME_VAR="B"</Condition>
            </Component>
            <Component Id="cmp3" Guid="{52737913-3452-42D2-99FE-71A60DAA425F}">
                <File Id="fil4C22841B1246538F82E2807574D642D2" KeyPath="yes" Source="$(var.baseDir)\A\myfile.txt" />
            </Component>
            <Component Id="cmp4" Guid="{52737913-3452-42D2-99FE-71A60DAA426F}">
                <File Id="fil4C22841B1246538F82E2807574D642D2" KeyPath="yes" Source="$(var.baseDir)\A\myfile2.txt" />
            </Component>
        </DirectoryRef>
    </Fragment>
    <Fragment>
        <ComponentGroup Id="MyComponent">
            <ComponentRef Id="cmp1" />
            <ComponentRef Id="cmp2" />
            <ComponentRef Id="cmp3" />
            <ComponentRef Id="cmp4" />
        </ComponentGroup>
    </Fragment>
</Wix>

Expected output is to also have the <Condition>SOME_VAR="A"</Condition> elements under the last two <Component/> tags.

I seem to be almost close and it seems something is off in my XSLT. Can someone provide any pointers?

CodePudding user response:

Your template:

<xsl:template match="wix:Directory[@Name='A']">
  <xsl:copy-of select="node()"/>
</xsl:template>

seems to be the problem. It only copies the complete context. I suppose you need to use apply-templates like this:

<xsl:template match="wix:Directory[@Name='A']">
  <xsl:apply-templates/>
</xsl:template>

So it will reach your <xsl:template match="wix:Component">

  • Related