Question

I am having Msbuild XML file like this.

<?xml version="1.0" encoding="utf-8"?> 
  <Project xmlns="schemas.microsoft.com/developer/msbuild/2003">
         <ItemGroup>
             <Notifications Include="someone@gmail.com"/>
         </ItemGroup>
    <ItemGroup> 
         <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll"> 
             <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination> 
         </Xcopy>
         <Xcopy Include="..\..\..\Release\Core.assembly.dll">
             <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
         </Xcopy>
         <Xcopy Include="..\..\..\Release\UIAssembly.dll"> 
             <Destination>"..\..\..\Anothercomponent\Folder1</Destination> 
         </Xcopy>
         <Xcopy Include="..\..\..\Release\Core.assembly.dll">
             <Destination>"..\..\..\Anothercomponent\depl\BOM</Destination>
         </Xcopy>
    </Itemgroup>
  </Project>

Actually i would like to group XCopy Itemgroup like this

      <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll;
                    ..\..\..\Release\\Core.assembly.dll;">
      <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
     </Xcopy>

     <Xcopy Include="..\..\..\Release\UIAssembly.dll;">
      <Destination>"..\..\..\Anothercomponent\Folder1</Destination>
     </Xcopy>

     <Xcopy Include="..\..\..\Release\Core.assembly.dll">
             <Destination>"..\..\..\Anothercomponent\depl\BOM</Destination>
     </Xcopy>

How to achieve it using Powershell or Msbuild or by some other mechanism

Was it helpful?

Solution

Here is an example how to do this using the Group-Object cmdlet. It will group the xcopy elements by Destination and combine the Include paths into a semi-colon separated string. The output is stored in a new XML document and saved to disk. This doesn't programatically update the original. You can just copy paste the new consolidated XML over you original XML.

Update Now that I see your whole file, I see it has a default namespace which causes problems with XPath. There are two ways to get around this problem.

  1. Use namespace agnostic xpath
  2. Use a namespace manager

Here is an updated example using namespace agnostic xpath. Also in order to get the indentation you are looking for we'll need to do some text file processing after the XML object processing.

$xml="Myinput.xml"
$tempXmlFile = "C:\New.xml"

$outXml = New-Object System.Xml.XmlDocument
$outXml.AppendChild($outXml.CreateElement("root")) > $null

$x = [xml] (Get-Content $xml)
$x.SelectNodes("//*[local-name()='Xcopy']") | Group-Object Destination | % {
    $includePaths = ($_.Group | Select-Object -ExpandProperty Include) -join ";"
    $element = $outXml.CreateElement("Xcopy")
    $element2 = $outXml.CreateElement("Destination")
    $element2.InnerText = $_.Name
    $element.AppendChild($element2) > $null
    $element.SetAttribute("Include", $includePaths)
    $outXml.DocumentElement.AppendChild($element) > $null
}
$outXml.Save($tempXmlFile)

$data = Get-Content $tempXmlFile | % {
    $search = 'Include="'
    $index = $_.IndexOf('Include="')
    if ($index -gt 0) { 
        $spaces = ( ' ' * ($index + $search.length) ) 
    }
    $_ -replace ';', ";`n${spaces}"
}
$data | Set-Content $tempXmlFile
& notepad $tempXmlFile

Creates output:

<root>
  <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll
                  ..\..\..\Release\Core.assembly.dll">
    <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
  </Xcopy>
  <Xcopy Include="..\..\..\Release\UIAssembly.dll">
    <Destination>"..\..\..\Anothercomponent\Folder1</Destination>
  </Xcopy>
  <Xcopy Include="..\..\..\Release\Core.assembly.dll">
    <Destination>"..\..\..\Anothercomponent\depl\BOM</Destination>
  </Xcopy>
</root>

OTHER TIPS

Starting from MSBuild 3.5 you can use ItemDefinitionGroup.

  <ItemDefinitionGroup>
    <Xcopy>
      <Destination>"..\..\..\Mycomponent\depl\BOM\Folder1</Destination>
    </Xcopy>
  </ItemDefinitionGroup>
  <ItemGroup>
    <Xcopy Include="..\..\..\Release\UtilitiesAssembly.dll" />
    <Xcopy Include="..\..\..\Release\Core.assembly.dll" />
    <Xcopy Include="..\..\..\Release\UIAssembly.dll;">
      <Destination>"..\..\..\Anothercomponent\Folder1</Destination>     
    </Xcopy>
  </ItemGroup>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top