如何通过XSLT复制Wix的ComponentGroup节点并修改目标属性
问题:修改Wix XML复制的ComponentGroup中第一个ComponentRef的Id
我需要复制Wix XML里的ComponentGroup节点,修改新节点的Id为AnotherGroup,同时要把复制得到的ComponentGroup里第一个ComponentRef的Id改成AnotherCptRefId。
原始XML:
<?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <ComponentGroup Id="SomeGroup"> <ComponentRef Id="cmp4CFDF03BB139F024CF278CD5B0CE2D89" /> <ComponentRef Id="cmp8ACD64282EEF7EAC19C62C7B2AFACA09" /> </ComponentGroup> </Fragment> </Wix>
我之前已经实现了复制ComponentGroup并修改新节点Id的XSLT代码:
<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" xmlns="http://schemas.microsoft.com/wix/2006/wi"> <xsl:output method="xml" indent="yes" /> <xsl:strip-space elements="*"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match='wix:Wix/wix:Fragment/wix:ComponentGroup'> <!--the original--> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> <!--duplicate--> <xsl:copy> <xsl:attribute name="Id">AnotherGroup</xsl:attribute> <xsl:apply-templates select="node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
期望输出:
<?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <ComponentGroup Id="SomeGroup"> <ComponentRef Id="cmp4CFDF03BB139F024CF278CD5B0CE2D89" /> <ComponentRef Id="cmp8ACD64282EEF7EAC19C62C7B2AFACA09" /> </ComponentGroup> <ComponentGroup Id="AnotherGroup"> <ComponentRef Id="AnotherCptRefId" /> <ComponentRef Id="cmp8ACD64282EEF7EAC19C62C7B2AFACA09" /> </ComponentGroup> </Fragment> </Wix>
请问该如何修改XSLT代码实现这个需求?
解决方案
修改后的XSLT代码如下:
<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" xmlns="http://schemas.microsoft.com/wix/2006/wi"> <xsl:output method="xml" indent="yes" /> <xsl:strip-space elements="*"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match='wix:Wix/wix:Fragment/wix:ComponentGroup'> <!-- 保留原始节点 --> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> <!-- 复制并修改后的节点 --> <xsl:copy> <xsl:attribute name="Id">AnotherGroup</xsl:attribute> <!-- 传递参数标记这是复制的组 --> <xsl:apply-templates select="node()"> <xsl:with-param name="isDuplicateGroup" select="true()"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <!-- 匹配复制组里的第一个ComponentRef,修改其Id --> <xsl:template match="wix:ComponentRef[1]"> <xsl:param name="isDuplicateGroup"/> <xsl:copy> <xsl:choose> <xsl:when test="$isDuplicateGroup"> <xsl:attribute name="Id">AnotherCptRefId</xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="@*"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:template> </xsl:stylesheet>
关键改动说明:
- 在复制ComponentGroup节点时,通过
<xsl:with-param>传递参数isDuplicateGroup,标记当前是复制出来的组,让后续模板知道需要特殊处理子节点。 - 添加专门匹配第一个
ComponentRef的模板,根据传入的参数判断场景:- 如果是复制组的第一个
ComponentRef,直接替换其Id属性为目标值。 - 否则保留原有属性,不做修改。
- 如果是复制组的第一个
这样既能保留原始XML的完整结构,又能精准修改复制组内指定节点的属性。
内容的提问来源于stack exchange,提问作者Billy
相关产品推荐
相关产品推荐

