The Answer to manipulating output of the HeatDirectory Task is to use XSLT. In the HeatDirectory task an attribute called Transforms
can be specified which points to a file containing XSLT instructions. To achieve the output I was asking for, the following XSLT code can be used:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output
method="xml"
indent="yes"/>
<xsl:variable name="ComponentGroup-Id" select="//wix:ComponentGroup/@Id"/>
<xsl:variable name="DestinationFolder" select="//wix:Component[1]/@Directory"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select ="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//wix:Directory">
<xsl:variable name="DirName" select="@Name" />
<xsl:copy>
<xsl:attribute name="Id">
<xsl:value-of select="$ComponentGroup-Id"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="$DirName"/>
</xsl:attribute>
<xsl:attribute name="Name">
<xsl:value-of select="$DirName"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="//wix:ComponentGroup">
<xsl:copy>
<xsl:attribute name="Id">
<xsl:value-of select="$ComponentGroup-Id"/>
</xsl:attribute>
<xsl:attribute name="Directory">
<xsl:value-of select="$DestinationFolder"/>
</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="//wix:Component">
<xsl:variable name="FilePath" select="current()/wix:File/@Source" />
<xsl:variable name="FileName" select="substring-after($FilePath,'\')" />
<xsl:variable name="Guid" select="@Guid" />
<xsl:copy>
<xsl:attribute name="Id">
<xsl:text>CMP_</xsl:text>
<xsl:choose>
<xsl:when test="contains($FileName,'\')">
<xsl:value-of select="substring-after($FileName,'\')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$FileName"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="Guid">
<xsl:value-of select="$Guid"/>
</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="//wix:File">
<xsl:variable name="FilePath" select="@Source" />
<xsl:variable name="FileName" select="substring-after($FilePath,'\')" />
<xsl:copy>
<xsl:attribute name="Id">
<xsl:choose>
<xsl:when test="contains($FileName,'\')">
<xsl:value-of select="substring-after($FileName,'\')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$FileName"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="KeyPath">
<xsl:text>yes</xsl:text>
</xsl:attribute>
<xsl:attribute name="Source">
<xsl:value-of select="$FilePath"/>
</xsl:attribute>
<xsl:if test="contains($FileName,'.dll')">
<xsl:attribute name="Assembly">.net</xsl:attribute>
<xsl:attribute name="AssemblyApplication">
<xsl:choose>
<xsl:when test="contains($FileName,'\')">
<xsl:value-of select="substring-after($FileName,'\')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$FileName"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="AssemblyManifest">
<xsl:choose>
<xsl:when test="contains($FileName,'\')">
<xsl:value-of select="substring-after($FileName,'\')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$FileName"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:if>
<xsl:attribute name="Compressed">
<xsl:text>no</xsl:text>
</xsl:attribute>
<xsl:attribute name="DiskId">
<xsl:text>$(var.SomeDiskID)</xsl:text>
</xsl:attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>