admin管理员组

文章数量:1410696

I am trying to transform an XML file using XSLT in MSBuild's TransformXml task. My goal is to modify a Wix XML file by adding a <RegistryValue> element inside each <Component> and remove KeyPath="yes" from <File>.

Input XML:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns=";>
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Component Id="cmp3E8A66A51C067CB532D96BDB574D5B62" Guid="{7DF9EBF3-A8FF-4A1D-BEEB-6A84A31A5484}">
                <File Id="fil2934E863A1FB7CCB3F2B4AE5D7638C21" KeyPath="yes" Source="test.json" />
            </Component>
            <Component Id="cmpAC81A7A6F463ADCB651789415E02A5EB" Guid="{67BA41FF-FF45-436B-9DF3-C311B061485B}">
                <File Id="fil9E171FDD3F525EDE194757D2A95D1311" KeyPath="yes" Source="test2.json" />
            </Component>
        </DirectoryRef>
    </Fragment>
</Wix>

Expected Output:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns=";>
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Component Id="cmp3E8A66A51C067CB532D96BDB574D5B62" Guid="{7DF9EBF3-A8FF-4A1D-BEEB-6A84A31A5484}">
                <RegistryValue Root="HKCU" Key="Key" Name="Installed" Type="integer" Value="1" KeyPath="yes"/>
                <File Id="fil2934E863A1FB7CCB3F2B4AE5D7638C21" Source="test.json" />
            </Component>
            <Component Id="cmpAC81A7A6F463ADCB651789415E02A5EB" Guid="{67BA41FF-FF45-436B-9DF3-C311B061485B}">
                <RegistryValue Root="HKCU" Key="Key" Name="Installed" Type="integer" Value="1" KeyPath="yes"/>
                <File Id="fil9E171FDD3F525EDE194757D2A95D1311" Source="test2.json" />
            </Component>
        </DirectoryRef>
    </Fragment>
</Wix>

What I've Tried:

I am using MSBuild's TransformXml task, but I need help writing the XSLT to achieve this transformation. I need an XSLT that will:

  1. Copy everything from the original XML.
  2. Insert a <RegistryValue> before the <File> element inside each <Component>.

Could someone help me with the correct XSLT for this transformation?

I am trying to transform an XML file using XSLT in MSBuild's TransformXml task. My goal is to modify a Wix XML file by adding a <RegistryValue> element inside each <Component> and remove KeyPath="yes" from <File>.

Input XML:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Component Id="cmp3E8A66A51C067CB532D96BDB574D5B62" Guid="{7DF9EBF3-A8FF-4A1D-BEEB-6A84A31A5484}">
                <File Id="fil2934E863A1FB7CCB3F2B4AE5D7638C21" KeyPath="yes" Source="test.json" />
            </Component>
            <Component Id="cmpAC81A7A6F463ADCB651789415E02A5EB" Guid="{67BA41FF-FF45-436B-9DF3-C311B061485B}">
                <File Id="fil9E171FDD3F525EDE194757D2A95D1311" KeyPath="yes" Source="test2.json" />
            </Component>
        </DirectoryRef>
    </Fragment>
</Wix>

Expected Output:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Component Id="cmp3E8A66A51C067CB532D96BDB574D5B62" Guid="{7DF9EBF3-A8FF-4A1D-BEEB-6A84A31A5484}">
                <RegistryValue Root="HKCU" Key="Key" Name="Installed" Type="integer" Value="1" KeyPath="yes"/>
                <File Id="fil2934E863A1FB7CCB3F2B4AE5D7638C21" Source="test.json" />
            </Component>
            <Component Id="cmpAC81A7A6F463ADCB651789415E02A5EB" Guid="{67BA41FF-FF45-436B-9DF3-C311B061485B}">
                <RegistryValue Root="HKCU" Key="Key" Name="Installed" Type="integer" Value="1" KeyPath="yes"/>
                <File Id="fil9E171FDD3F525EDE194757D2A95D1311" Source="test2.json" />
            </Component>
        </DirectoryRef>
    </Fragment>
</Wix>

What I've Tried:

I am using MSBuild's TransformXml task, but I need help writing the XSLT to achieve this transformation. I need an XSLT that will:

  1. Copy everything from the original XML.
  2. Insert a <RegistryValue> before the <File> element inside each <Component>.

Could someone help me with the correct XSLT for this transformation?

Share Improve this question edited Mar 4 at 13:12 Nicola Zreinh asked Mar 4 at 12:59 Nicola ZreinhNicola Zreinh 314 bronze badges 3
  • While asking an XSLT question you need to provide a minimal reproducible example: (1) Well-formed input XML with all relevant namespaces. (2) Your logic, and complete executable XSLT stylesheet that tries to implement it. (3) Desired output, based on the sample XML in the #1 above. (4) XSLT processor and its conformance with the XSLT standards: 1.0, 2.0, 3.0, or 4.0. – Yitzhak Khabinsky Commented Mar 4 at 13:02
  • I updated the example, thanks – Nicola Zreinh Commented Mar 4 at 13:07
  • Did you have a chance to try the proposed solutions? – Yitzhak Khabinsky Commented Mar 5 at 12:56
Add a comment  | 

3 Answers 3

Reset to default 0

I believe the correct answer is:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3./1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft/wix/2006/wi">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<!-- identity transform -->
<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="@*"/>
        <RegistryValue xmlns="http://schemas.microsoft/wix/2006/wi" Root="HKCU" Key="Key" Name="Installed" Type="integer" Value="1" KeyPath="yes"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
    
<xsl:template match="wix:File/@KeyPath"/>

</xsl:stylesheet>

Please try the following solution leveraging a so called Identity Transform XSLT pattern.

XML

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft/wix/2006/wi">
    <Fragment>
        <DirectoryRef Id="INSTALLFOLDER">
            <Component Id="cmp3E8A66A51C067CB532D96BDB574D5B62"
                       Guid="{7DF9EBF3-A8FF-4A1D-BEEB-6A84A31A5484}">
                <File Id="fil2934E863A1FB7CCB3F2B4AE5D7638C21" KeyPath="yes"
                      Source="test.json"/>
            </Component>
            <Component Id="cmpAC81A7A6F463ADCB651789415E02A5EB"
                       Guid="{67BA41FF-FF45-436B-9DF3-C311B061485B}">
                <File Id="fil9E171FDD3F525EDE194757D2A95D1311" KeyPath="yes"
                      Source="test2.json"/>
            </Component>
        </DirectoryRef>
    </Fragment>
</Wix>

XSLT 1.0

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3./1999/XSL/Transform"
                xmlns:ns1="http://schemas.microsoft/wix/2006/wi">
    <xsl:output omit-xml-declaration="no" indent="yes" encoding="utf-8"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="ns1:Component">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:element name="RegistryValue">
                <xsl:attribute name="Root">HKCU</xsl:attribute>
                <xsl:attribute name="Key">Key</xsl:attribute>
                <xsl:attribute name="Name">Installed</xsl:attribute>
                <xsl:attribute name="Type">integer</xsl:attribute>
                <xsl:attribute name="Type">1</xsl:attribute>
                <xsl:attribute name="KeyPath">yes</xsl:attribute>
            </xsl:element>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ns1:File">
        <xsl:copy>
            <xsl:copy-of select="@*[not(local-name()='KeyPath')]"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Output

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft/wix/2006/wi">
  <Fragment>
    <DirectoryRef Id="INSTALLFOLDER">
      <Component Id="cmp3E8A66A51C067CB532D96BDB574D5B62" Guid="{7DF9EBF3-A8FF-4A1D-BEEB-6A84A31A5484}">
        <RegistryValue Root="HKCU" Key="Key" Name="Installed" Type="1" KeyPath="yes" />
        <File Id="fil2934E863A1FB7CCB3F2B4AE5D7638C21" Source="test.json" />
      </Component>
      <Component Id="cmpAC81A7A6F463ADCB651789415E02A5EB" Guid="{67BA41FF-FF45-436B-9DF3-C311B061485B}">
        <RegistryValue Root="HKCU" Key="Key" Name="Installed" Type="1" KeyPath="yes" />
        <File Id="fil9E171FDD3F525EDE194757D2A95D1311" Source="test2.json" />
      </Component>
    </DirectoryRef>
  </Fragment>
</Wix>

This XSLT is a customized identity transform with a specialized template matching the Component element and adding RegistryValue child element.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3./1999/XSL/Transform" 
    xmlns:wix="http://schemas.microsoft/wix/2006/wi">

    <xsl:output indent="yes"/>

    <!--by default, copy everything and push children through templates -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!--for every wix Component element, copy the attributes, add a RegistryValue element, then copy the rest (File elements)-->
    <xsl:template match="wix:Component">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <wix:RegistryValue Root="HKCU" Key="Key" Name="Installed" Type="integer" Value="1" KeyPath="yes"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!--drop the KeyPath attribute -->
    <xsl:template match="wix:File/@KeyPath"/>

</xsl:stylesheet>

本文标签: Transforming Wix XML with XSLT in MSBuild to Add RegistryValueStack Overflow