msbuildmsbuild-4.0itemgroup

How to get all the metadata keys for any ItemGroup item?


Is there a way to get all the metadata keys associated with a given item?

I want to do something like the following.

Given:

  <ItemGroup>
    <MyItems Include="item1">
      <key1>val1</key1>
      <key2>val2</key2>
      <key3>val3</key3>
    </MyItems>
    <MyItems Include="item2">
      <key4>val4</key4>
    </MyItems>
  </ItemGroup>

Be able to determine that item1 has metadata available for key1, key2, and key3, and that item2 has metadata available for key4, without knowing what the names of those keys actually are.

In effect, I'm trying to use the metadata to specify attributes that I have no idea about, and then trying to figure out a way to check to see what attributes have been specified.

Put another way, I believe the metadata of each item is just a hash containing key/value pairs and I'm trying to figure out what all the keys are.

Anyone know how to do this with msbuild?

Thanks


Solution

  • I ended up solving this using a custom inline task similar to the following:

    <UsingTask
      TaskName="GetMetadataTask"
      TaskFactory="CodeTaskFactory"
      AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
      <ParameterGroup>
        <MyItemGroup ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
        <MetadataString Output="true" />
      </ParameterGroup>
      <Task>
        <Using Namespace="System"/>
        <Code Type="Fragment" Language="cs">
          <![CDATA[
              StringBuilder command = new StringBuilder();
              foreach (ITaskItem item in MyItemGroup )
              {
                  command.AppendFormat("ItemName={0}\r\n", item);
                  foreach (string parameter in item.MetadataNames)
                  {
                      command.AppendFormat("  {0}={1}\r\n", parameter, item.GetMetadata(parameter));
                  }
                  command.AppendFormat("\r\n");
              }
              MetadataString = command.ToString();
          ]]>
        </Code>
      </Task>
    </UsingTask>
    

    Note that the above will also include all the default metadata that MSBuild automatically adds to every item in an itemgroup (like FullPath, RootDir, Filename, etc). In my implementation I added an extra check to ignore those metadata items that I didn't care about

    Sample usage:

    <GetMetadataTask MyItemGroup="@(YourItemGroup)">
      <Output TaskParameter="MetadataString" PropertyName="YourMetadataString"/>
    </GetMetadataTask>
    <Message Text="$(YourMetadataString)" />
    

    To see message output in Visual Studio's Output window, you may need to change your MSBuild output verbosity to at least Normal.