Wix Harvest使用XSLT扁平化子文件夹时组件条件未生效问题
WiX Heat目录收割XSLT转换失效问题排查与修正
问题背景
现有目录结构如下:
- 根目录
rootfolder下直接存放myfile.txt、myfile2.txt两个文件 - 根目录下包含子文件夹
A,内部存放同名但内容不同的两个对应文件
使用heat.exe执行以下命令收割目录,生成rootfolder.wxs文件:
"heat.exe" dir ".\rootfolder" -v -cg MyComponent -gg -scom -sreg -sfrag -srd -dr MyDirectoryRef -var var.baseDir -out rootfolder.wxs
需求说明
安装时根据用户选择做二选一部署:
- 要么将子文件夹A内的两个文件安装到
MyDirectoryRef指向的最终安装目录 - 要么直接安装rootfolder根目录下的对应文件
- 实现要求:扁平化A子文件夹的目录层级,给两组组件分别添加互斥的安装条件
预期与实际结果
- 预期转换效果:源路径包含A的组件(cmp3、cmp4)添加
<Condition>SOME_VAR="A"</Condition>条件,根目录下的组件(cmp1、cmp2)添加<Condition>SOME_VAR="B"</Condition>条件,同时移除A目录的层级包裹 - 实际故障:转换输出后仅根目录下的两个组件成功添加了对应条件,从A目录提取出的两个组件未添加预期的条件元素
故障根因
heat生成的原始WXS结构存在两个容易被忽略的特点,大部分失效的XSLT都踩了对应的坑:
- 子目录A下的组件默认是嵌套在
<Directory Id="xxx" Name="A">节点内部的,如果XSLT的Component匹配规则写死了一级层级(比如仅匹配DirectoryRef直接子级的Component),子目录下的嵌套Component根本不会进入条件注入的匹配逻辑 - Component节点本身不存储源路径信息,源路径是写在Component内部的File子节点的
Source属性上。如果判断路径时读取Component自身的属性,会导致子目录下组件的路径判断逻辑永远不触发。
可直接使用的修正XSLT
<?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"> <!-- 全局身份模板,默认复制所有节点、属性与内容 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 扁平化A目录:透传A目录节点内部的所有组件,删除A目录本身的层级包裹 --> <xsl:template match="wix:Directory[@Name='A']"> <xsl:apply-templates select="node()"/> </xsl:template> <!-- 匹配所有层级的Component组件,注入对应互斥条件 --> <xsl:template match="wix:Component"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:choose> <!-- 读取组件内File节点的Source属性,判断是否属于A目录下的文件 --> <xsl:when test="contains(wix:File/@Source, '\A\')"> <Condition>SOME_VAR="A"</Condition> </xsl:when> <xsl:otherwise> <Condition>SOME_VAR="B"</Condition> </xsl:otherwise> </xsl:choose> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
排查校验要点
- 不要给Component匹配规则增加层级限制,避免漏掉嵌套在子目录下的组件
- 路径判断必须读取Component下File节点的
Source属性,不要尝试读取Component自身不存在的路径属性 - 处理A目录节点时不要直接删除整个节点,要透传节点内部的Component内容,避免A目录下的组件被意外丢弃
内容的提问来源于stack exchange,提问作者Vrushank
相关产品推荐
相关产品推荐

