Hank
Hank

Reputation: 2476

Remove node or children based on another child

I'm using Wix Head to harvest my output directory with some third-party dependencies, but still trying to wrap my head around XSLT transformations.

What I have roughly have:

<Wix>
  <Fragment>
    <DirectoryRef Id="INSTALLFOLDER">
      <Component Id="1">
        <File Source="Valid.dll"/>
        <RegistryValue />
      </Component>
      <Component Id="2">
        <File Source="Valid.pdb"/>
      </Component>
      <Component Id="3">
        <File Source="XML.dll"/>
        <RegistryValue />
        <RegistryValue />
        <RegistryValue />
      </Component>
    </DirectoryRef> 
  </Fragment>
  <Fragment>
    <ComponentGroup Id="Published">
      <Component Id="1" />
      <Component Id="2" />
      <Component Id="3" />
    </ComponentGroup>
  </Fragment>
</Wix>

What I want:

<Wix>
  <Fragment>
    <DirectoryRef Id="INSTALLFOLDER>
      <Component Id="1">
        <File Source="Valid.dll"/>
        <RegistryValue />
      </Component>
      <Component Id="3">
        <File Source="XML.dll"/>
      </Component>
    <DirectoryRef> 
  </Fragment>
  <Fragment>
    <ComponentGroup Id="Published">
      <Component Id="1" />
      <Component Id="3" />
    </ComponentGroup>
  </Fragment>
</Wix>

My XSLT so far but the templates don't apply to each other. They do their own thing. They are in wix namespace but I simplified it for this question.

<xsl:stylesheet version="1.0">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

    <xsl:strip-space elements="*"/>

    <xsl:key name="pdbs" match="Component[contains(File/@Source, 'pdb')]" use="@Id"/>
    <xsl:key name="unneededRegistry" match="Component[not(contains(File/@Source, 'Valid'))]" use="@Id"/>

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

    <!-- Remove PDBs -->
    <xsl:template match="*[self::Component or self::ComponentRef][key('pdbs',@Id']"/>

    <!-- Remove everything but file in non-core dlls -->
    <xsl:template match="Component[key('unneededRegistry',@Id)]">
        <xsl:copy>
            <xsl:apply-template select="@*|File"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

I feel like I'm close to getting it but I've tried so much to no avail. I need to remove all the components with pdb in the file and remove all nodes that aren't File on the Valid ones.

Upvotes: 1

Views: 68

Answers (1)

Joel M. Lamsen
Joel M. Lamsen

Reputation: 7173

Below is a modified style sheet.

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

    <xsl:strip-space elements="*"/>

    <xsl:key name="pdbs" match="Component[contains(File/@Source, 'pdb')]" use="@Id"/>
    <!-- I have removed this key
    <xsl:key name="unneededRegistry" match="Component[not(contains(File/@Source, 'Valid'))]" use="@Id"/>
    -->

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

    <!-- Remove PDBs,
         have included a predicate here instead of a key
    -->
    <xsl:template match="*[self::Component or self::ComponentRef]
        [contains(File/@Source, 'pdb')]"/>

    <!-- Remove everything but file in non-core dlls,
         have included a predicate here instead of a key
    -->
    <xsl:template match="DirectoryRef/Component[not(contains(File/@Source, 'Valid'))]">
        <xsl:copy>
            <xsl:apply-templates select="@*|File"/>
        </xsl:copy>
    </xsl:template>

    <!-- added a rule here to delete target Component nodes -->
    <xsl:template match="ComponentGroup/Component[key('pdbs', @Id)]"/>
</xsl:stylesheet>

See it in action here.

Upvotes: 1

Related Questions