Cross Element Groups in MSBuild

Given something like this.

<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <ConfigFiles Include="*.config" /> <DatabaseConfig Include="ABC"> <Database>DB1</Database> <CsString>Database</CsString> </DatabaseConfig> <DatabaseConfig Include="DEF"> <Database>DB2</Database> <CsString>Logging</CsString> </DatabaseConfig> </ItemGroup> <Target Name="test" > <!-- Some sort of join here (or somewhere)... --> <Message Text=" %(Combined.ConfigFile) %(Combined.Database) " /> </Target> </Project> 

I would like Output to be something like this. (considering two files: one.config and two.config)

 one.config DB1 two.config DB1 one.config DB2 two.config DB2 

(order is not important, just a complete Cartesian product of two elements)

+4
source share
2 answers

This seems like a neat solution:

 <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <ConfigFiles Include="*.config" /> <DatabaseConfig Include="ABC"> <Database>DB1</Database> <CsString>Database</CsString> </DatabaseConfig> <DatabaseConfig Include="DEF"> <Database>DB2</Database> <CsString>Logging</CsString> </DatabaseConfig> </ItemGroup> <Target Name="test" > <ItemGroup> <Combined Include="@(DatabaseConfig)"> <ConfigFile>%(ConfigFiles.Identity)</ConfigFile> </Combined> </ItemGroup> <Message Text=" %(Combined.ConfigFile) %(Combined.Database) " /> </Target> </Project> 
+5
source

There is a way that you can do this with minimal modifications to your existing code sample. You can combine the metadata from the ConfigFiles elements and the DatabaseConfig elements into a new "combined" element, and then output this "combined" element.

To combine metadata, use batch target when the batch target is run once for each DatabaseConfig element. You can then call another target to output the combined metadata to get the output you describe. Take a look at my extension of your code sample to find out how this will all work:

 <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <ConfigFiles Include="*.config" /> <DatabaseConfig Include="ABC"> <Database>DB1</Database> <CsString>Database</CsString> </DatabaseConfig> <DatabaseConfig Include="DEF"> <Database>DB2</Database> <CsString>Logging</CsString> </DatabaseConfig> </ItemGroup> <Target Name="test" DependsOnTargets="test_setup;test_output" > <!-- Logic here runs after targets listed in "DependsOnTargets". --> </Target> <!-- This will run once for each "DatabaseConfig" item. --> <Target Name="test_setup" Outputs="%(DatabaseConfig.Identity)"> <PropertyGroup> <!-- Specify the Database for the current DatabaseConfig item --> <CurrentDb>%(DatabaseConfig.Database)</CurrentDb> </PropertyGroup> <ItemGroup> <!-- Add a new CombinedOutput item with each run, combining metadata. --> <CombinedOutput Include=" %(ConfigFiles.FileName)%(ConfigFiles.Extension) $(CurrentDb) " /> </ItemGroup> </Target> <Target Name="test_output"> <!-- Output the combined metadata from the CombinedOutput items --> <Message Text=" %(CombinedOutput.Identity) " /> </Target> </Project> 

What happens in the example:

  • The test target now simply serves to invoke two other goals for the job: test_setup and test_output
  • The target test_setup unloaded and creates a new CombinedOutput .
  • The test_output is called after test_setup to output CombinedOutput metadata.

Exiting test_output :

 one.config DB1 two.config DB1 one.config DB2 two.config DB2 
+3
source

All Articles