我正在努力将Windows服务VDPROJ迁移到WiX.
我能够使用HEAT将Windows Service项目的输出收集到片段中.目前,为了使我的自定义操作正常工作,我手动将一些生成的GUID从Heat生成的文件更改为主Product.wxs中引用的已知字符串.
我需要在每个构建上以编程方式执行此操作,而不是依赖于手动干预,因为我需要将WiX项目集成到我们的连续构建服务器中.
根据我的研究,我可以在HEAT的输出上使用XSLT转换来实现我的需要,但是我很难让我的XSLT转换工作.
这是生成的片段的一部分,不使用XSLT转换
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
[...]
<Fragment>
<ComponentGroup Id="Windows.Service.Binaries">
<ComponentRef Id="ComponentIdINeedToReplace" />
[...]
</ComponentGroup>
</Fragment>
[...]
<Fragment>
<ComponentGroup Id="CG.WinSvcContent">
<Component Id="ComponentIdINeedToReplace" Directory="TARGETDIR" Guid="{SOMEGUID}">
<File Id="FileIdINeedToReplace" Source="$(var.Windows.Service.TargetDir)\Windows.Service.exe" />
</Component>
[...]
</ComponentGroup>
</Fragment>
[...]
</Wix>
Run Code Online (Sandbox Code Playgroud)
我将HEAT prebuild命令修改为:
"$(WIX)bin\heat.exe" project "$(ProjectDir)\..\Windows.Service\Windows.Service.csproj" -gg -pog Binaries -pog Symbols -pog Content -cg CG.WinSvcContent -directoryid "TARGETDIR" -t "$(ProjectDir)Resources\XsltTransform.xslt" -out "$(ProjectDir)Fragments\Windows.Service.Content.wxs"
Run Code Online (Sandbox Code Playgroud)
并编写了以下XSLT来实现两件事:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable
name="vIdToReplace"
select="//ComponentGroup[@Id='CG.WinSvcContent']/Component/File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]/../@Id" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="node[@Id=vIdToReplace]">
<xsl:copy-of select="@*[name()!='Id']"/>
<xsl:attribute name="Id">C_Windows_Service_exe</xsl:attribute>
</xsl:template>
<xsl:template
match="//ComponentGroup[@Id='CG.WinSvcContent']/Component/File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]">
<xsl:copy-of select="@*[name()!='Id']"/>
<xsl:attribute name="Id">Windows_Service_exe</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
如何修改我的XSLT以实现我的需求?
Tim*_*m C 10
我担心你的XSLT会遇到很多问题.第一个是名称空间.在你的wix XML文件中,所有元素都在命名空间" http://schemas.microsoft.com/wix/2006/wi "中,但在XSLT中没有提到该命名空间,这意味着你试图匹配一个命名元素,它只匹配NO命名空间中的那些,而wix文件不是这种情况.
你需要为XSLT添加相应的命名空间声明,就像这样
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wi="http://schemas.microsoft.com/wix/2006/wi">
Run Code Online (Sandbox Code Playgroud)
然后,在引用命名元素的位置,使用此声明的前缀作为前缀.例如,与File匹配的模板将如下所示
<xsl:template match="wi:ComponentGroup[@Id='CG.WinSvcContent']/wi:Component/wi:File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]">
Run Code Online (Sandbox Code Playgroud)
现在,你在这个模板中也遇到了一个问题,因为你要做的第一件事是输出一个属性,但是你此时并没有真正复制过File元素,所以你可能会收到一个错误,因为它不会有什么要添加属性.因此,模板可能需要看起来像这样
<xsl:template match="wi:ComponentGroup[@Id='CG.WinSvcContent']/wi:Component/wi:File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]">
<xsl:copy>
<xsl:attribute name="Id">Windows_Service_exe</xsl:attribute>
<xsl:copy-of select="@*[name()!='Id']"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
(我在这里添加了一个xsl:apply-templates,但在这种情况下可能没有必要,如果File元素没有子元素)
您也遇到了以前模板的问题
<xsl:template match="node[@Id=vIdToReplace]">
Run Code Online (Sandbox Code Playgroud)
我猜你的意思是在这里使用"node()"而不是"node",因为"node"本身会在字面上寻找一个名为"node"的元素,其中没有.但主要问题是你将@Id与vIdToReplace进行比较.在这种情况下,当你真的想要将它与你的变量进行比较时,它正在寻找一个名为vIdToReplace的元素.正确的语法是$ vIdToReplace
<xsl:template match="node()[@Id=$vIdToReplace]">
Run Code Online (Sandbox Code Playgroud)
可是等等!如果您使用的是XSLT 1.0,则会出现错误.您不能在XSLT 1.0中使用模板匹配中的变量.它只适用于XSLT 2.0.你可以做的只是将长表达式粘贴到模板匹配中:
<xsl:template match="node()[@Id=//wi:ComponentGroup[@Id='CG.WinSvcContent']/wi:Component[wi:File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]]/@Id]">
Run Code Online (Sandbox Code Playgroud)
但这看起来相当笨拙.或者,您可以定义一个键来查找包含您要替换的ID 的Component元素:
<xsl:key name="vIdToReplace"
match="wi:ComponentGroup[@Id='CG.WinSvcContent']/wi:Component[wi:File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]]"
use="@Id"/>
Run Code Online (Sandbox Code Playgroud)
然后,您可以在模板匹配中使用此键,以检查当前@Id 的Component元素是否存在
<xsl:template match="node()[key('vIdToReplace', @Id)]">
Run Code Online (Sandbox Code Playgroud)
在这种情况下,这是完整的XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wi="http://schemas.microsoft.com/wix/2006/wi">
<xsl:key name="vIdToReplace"
match="wi:ComponentGroup[@Id='CG.WinSvcContent']/wi:Component[wi:File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]]"
use="@Id"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="node()[key('vIdToReplace', @Id)]">
<xsl:copy>
<xsl:attribute name="Id">C_Windows_Service_exe</xsl:attribute>
<xsl:copy-of select="@*[name()!='Id']"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="wi:ComponentGroup[@Id='CG.WinSvcContent']/wi:Component/wi:File[contains(@Source,'Windows.Service.exe') and not(contains(@Source,'config'))]">
<xsl:copy>
<xsl:attribute name="Id">Windows_Service_exe</xsl:attribute>
<xsl:copy-of select="@*[name()!='Id']"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
应用于XML时,将输出以下内容
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
[...]
<Fragment>
<ComponentGroup Id="Windows.Service.Binaries">
<ComponentRef Id="C_Windows_Service_exe"/>
[...]
</ComponentGroup>
</Fragment>
[...]
<Fragment>
<ComponentGroup Id="CG.WinSvcContent">
<Component Id="C_Windows_Service_exe" Directory="TARGETDIR" Guid="{SOMEGUID}">
<File Id="Windows_Service_exe" Source="$(var.Windows.Service.TargetDir)\Windows.Service.exe"/>
</Component>
[...]
</ComponentGroup>
</Fragment>
[...]
</Wix>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2895 次 |
| 最近记录: |