Search code examples
xmlmsbuildbuild-processmsbuildcommunitytasks

XmlMassUpdate - how NOT to add xmlns?


I'm using Nightly build 1.3.0.477 of MSBuild Community Tasks and I'm having problem with XmlMassUpdate.

Here's what I want to do:

for each project, if it does not reference CommonAssemblyInfo.cs file, add that reference.

I'm doing it like this:

<Message Text="Path is $(MSBuildCommunityTasksPath)" Importance="normal" />
<!---->
<XmlMassUpdate ContentFile="%(DotNetProjects.FullPath)"
               ContentRoot="msb:Project/msb:ItemGroup[2]/msb:Compile[1]"
               NamespaceDefinitions="msb=http://schemas.microsoft.com/developer/msbuild/2003"
               SubstitutionsFile="$(BuildFolder)CommonAssemblyInfo.substitution"
               SubstitutionsRoot="ItemGroup/Compile" />

my substitution file looks like this:

<ItemGroup>
    <Compile Include="..\..\CommonAssemblyInfo.cs" >
        <Link>Properties\CommonAssemblyInfo.cs</Link>
    </Compile>
</ItemGroup>

the issue is, when I run the target, it adds empty xmlns to the Link tag, which is illegal.

<ItemGroup>
<Compile Include="Class1.cs">
  <Link xmlns="">Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>

How do I tell it not to do it?


Solution

  • The short answer is you can't, the replace task always uses an empty namespace even if the substitution file's node has a namespace.

    see: line 380 in XmlMassUpdate.cs destinationParentNode.AppendChild(mergedDocument.CreateNode(XmlNodeType.Element, nodeToModify.Name, String.Empty)

    As an alternative you could use the XSLT task to transform the xml file.

    I've included a basic example of how this might be done, but I'm not particularly proficient with XSLT so its a little hacked together.

    <xsl:stylesheet
        version="1"
        xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
        xmlns:msb="http://schemas.microsoft.com/developer/msbuild/2003"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        >
    
        <xsl:output indent="yes"
                standalone="yes"
                method="xml"
                encoding="utf-8"
                />
    
        <xsl:template match="/msb:Project/msb:ItemGroup[1]">
            <ItemGroup>
                <Compile Include="..\..\CommonAssemblyInfo.cs">
                    <Link>Properties\CommonAssemblyInfo.cs</Link>
                </Compile>
            </ItemGroup>
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    And in the build file.

    <Xslt Inputs="input.xml"
          Output="output.xml"
          Xsl="transform.xslt"
          />