Filter an existing itemgroup so it only includes files that match some condition

12,786

Solution 1

<ItemGroup>
  <Filtered Include="@(None)" Condition="'%(Extension)' == '.ext'" />
</ItemGroup>

Solution 2

For advanced filtering I suggest using the RegexMatch from MSBuild Community Tasks.

In this Example we will Filter for Versionnumbers

    <RegexMatch Input="@(Items)" Expression="\d+\.\d+\.\d+.\d+">
        <Output ItemName ="ItemsContainingVersion" TaskParameter="Output" />
    </RegexMatch>

Install MSBuild Community Tasks via Nuget: PM> Install-Package MSBuildTasks or download it here

Then Import it in your MSBuild Script:

<PropertyGroup>
    <MSBuildCommunityTasksPath>..\.build\</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import Project="$(MSBuildCommunityTasksPath)MsBuild.Community.Tasks.Targets" />
Share:
12,786

Related videos on Youtube

Kaleb Pederson
Author by

Kaleb Pederson

Software Craftsman, Husband, Father.

Updated on September 24, 2022

Comments

  • Kaleb Pederson
    Kaleb Pederson over 1 year

    How do you filter an existing ItemGroup based on a specific condition, such as file extension or the item's metadata?

    For this example, I'll use the file extension. I'm trying to filter the 'None' ItemGroup defined by VS so that my target can operate on all files of a given extension.

    For example, the following may be defined:

    <ItemGroup>
        <None Include="..\file1.ext" />
        <None Include="..\file2.ext" />
        <None Include="..\file.ext2" />
        <None Include="..\file.ext3" />
        <None Include="..\file.ext4" />
    </ItemGroup>
    

    I want to filter the 'None' ItemGroup above so it only includes the ext extension. Note that I do not want to specify all the extensions to exclude, as they'll vary per project and I'm trying to make my target reusable without modification.

    I've tried adding a Condition within a target:

    <Target Name="Test">
        <ItemGroup>
            <Filtered
                Include="@(None)"
                Condition="'%(Extension)' == 'ext'"
                />
        </ItemGroup>
        <Message Text="None: '%(None.Identity)'"/>
        <Message Text="Filtered: '%(Filtered.Identity)'"/>
    </Target>
    

    But sadly, it doesn't work. I get the following for output:

    Test:
      None: '..\file1.ext'
      None: '..\file2.ext'
      None: '..\file.ext2'
      None: '..\file.ext3'
      None: '..\file.ext4'
      Filtered: ''
    
    • Ilya Kozhevnikov
      Ilya Kozhevnikov over 11 years
      I believe %(Extension) needs to be '.ext'
    • Ilya Kozhevnikov
      Ilya Kozhevnikov
      I mean it literally needs to be '.ext', as in with a dot as first char, works just fine then.
  • Marcin Wisnicki
    Marcin Wisnicki over 8 years
    This doesn't work for me. error MSB4190: The reference to the built-in metadata "Extension" at posi tion 1 is not allowed in this condition "'%(Extension)' == '.ext'".
  • VeeTheSecond
    VeeTheSecond almost 6 years
    I second the <Target> comment, with one addition: In a normal programming language, you would expect the <Filtered> ItemGroup to be scoped to the <Target> it is contained in. Not so in MSBuild: If you define your <Filtered> inside a target, it will be available to other targets, so if you need the ItemGroup in another target, just set your BeforeTargets attribute for the new <Target> to be the target where you need the ItemGroup.
  • Mostafa Armandi
    Mostafa Armandi almost 4 years
    @MarcinWisnicki make sure you put the ItemGroup into a target when you want to access well-known item metadata. Otherwise you get that error.