msbuildmsbuild-taskmsbuild-4.0msbuildcommunitytasksmsbuildextensionpack

It is possible to do this kind of conversion with msbuild


It is possible to do this kind of conversion with msbuild? Transforming metadata into items?

This:

<ItemGroup>
   <Group Include="G1">
      <A>1</A>
      <B>1</B>
    </Group>

    <Group Include="G2">
       <A>2</A>
       <B>2</B>
    </Group>
</ItemGroup>

To this:

<ItemGroup>
    <A>1</A>
    <A>2</A>

    <B>1</B>
    <B>2</B>
</ItemGroup>

Solution

  • You can use batching:

    This creates the new item groups A abd B based on Group. The new item groups don't have to use the same name as the metadata. Set ItemName in CreateItem/Output to use a different name.

    <?xml version="1.0" encoding="utf-8"?>
    <Project
        xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
        ToolsVersion="4.0"
        DefaultTargets="Default">
    
        <ItemGroup>
            <Group Include="G1">
                <A>1</A>
                <B>1</B>
            </Group>
            <Group Include="G2">
                <A>2</A>
                <B>2</B>
            </Group>
        </ItemGroup>
    
        <Target Name="Default">
            <Message Text="@(Group)" Importance="High" />
    
            <CreateItem Include="%(Group.A)">
                <Output TaskParameter="Include" ItemName="A" />
            </CreateItem>
            <CreateItem Include="%(Group.B)" AdditionalMetadata="From=%(Group.Identity)">
                <Output TaskParameter="Include" ItemName="B" />
            </CreateItem>
    
            <Message Text="A=@(A)" Importance="High" />
            <Message Text="B=@(B):%(B.From)" Importance="High" />
        </Target>
    
    </Project>
    

    The new "B" group also defines a metadata item called From that gives each item the original item group name it was copied from.

    Update: With msbuild 3.5 or newer you can also use this instead of CreateItem:

    <ItemGroup>
        <A Include="%(Group.A)" />
        <B Include="%(Group.B)">
            <From>%(Group.Identity)</From>
        </B>
    </ItemGroup>