Метаданные MSBuild для объединенных групп элементов

У меня есть две группы предметов, к которым я хочу присоединиться:

  <ItemGroup>
<ServerTypeA Include="ServerA;ServerB;">
  <MetaDataA>A</MetaDataA>
</ServerTypeA>
</ItemGroup>

  <ItemGroup>
<ServerTypeB Include="ServerB;ServerC;">
  <MetaDataB>B</MetaDataB>
</ServerTypeB>
</ItemGroup>

Использование обычного соединения даст мне коллекцию из 4 элементов:

ServerA with Metadata A;
ServerB with Metadata A;
ServerB with Metadata B;
ServerC with Metadata B;

Как я могу создать следующую коллекцию:

ServerA with Metadata A
ServerB with Metadata A & B
ServerC with Metadata B

person sagie    schedule 18.01.2011    source источник


Ответы (1)


Возможно. Вы должны выполнить объединение вручную.

Вот пример того, как это сделать (требуется msbuild 3.5 или выше):

<ItemGroup>
  <ServerTypeA Include="ServerA;ServerB;">
    <MetaDataA>A</MetaDataA>
  </ServerTypeA>

  <ServerTypeB Include="ServerB;ServerC;">
    <MetaDataB>B</MetaDataB>
  </ServerTypeB>
</ItemGroup>

<Target Name="JoinServers" DependsOnTargets="ProcessServerTypeA;ProcessServerTypeB">
  <Message Text="%(Joined.Identity) Metadata: %(Joined.MetaDataA)%(Joined.MetaDataB)"/>
</Target>

<!--Create -->
<Target Name="ProcessServerTypeA">
  <ItemGroup>
    <Joined Include="%(ServerTypeA.Identity)">
      <MetaDataA>%(ServerTypeA.MetaDataA)</MetaDataA>
    </Joined>
  </ItemGroup>
</Target>

<!--Need to batch at the target level for this to work-->
<Target Name="ProcessServerTypeB" Inputs="@(ServerTypeB)" Outputs="%(ServerTypeB.Identity)'">

  <PropertyGroup>
    <!--Create Temporary Properties for the Item Metadata-->
    <TempItemName>%(ServerTypeB.Identity)</TempItemName>
    <TempMetaDataB>%(ServerTypeB.MetaDataB)</TempMetaDataB>
    <!--Does the current item already exist?-->
    <TempIsDuplicate Condition="'%(Joined.Identity)' == '$(TempItemName)'">True</TempIsDuplicate>
  </PropertyGroup>

  <ItemGroup>
    <!--Update the existing item's metadata if this is a duplicate-->
    <!--Don't provide the include attribute.  This will allow you to update existing items metadata-->
    <!--Have to reference %(Joined.Identity) in the condtion to ensure we only update the correct item-->
    <!--You cannot directly reference metadata from ServerTypeB here.  Hence the need for the temp Properties-->
    <Joined Condition="'%(Joined.Identity)' == '$(TempItemName)'">
      <MetaDataB>$(TempMetaDataB)</MetaDataB>
    </Joined>

    <!--Create a new item if current item is not a duplicate-->
    <Joined Include="$(TempItemName)" Condition="'$(TempIsDuplicate)' != 'True'">
      <MetaDataB>$(TempMetaDataB)</MetaDataB>
    </Joined>
  </ItemGroup>
</Target>

Запуск цели JoinServers приведет к следующему выводу:

ServerA Metadata: A
ServerB Metadata: AB
ServerC Metadata: B

Обновить с лучшим ответом

Этот вопрос указал мне на гораздо более простое решение.

В основном вы используете модификаторы преобразования с %(Identity) для выполнения соединения.

Вы можете заменить все 3 цели сверху на следующие, чтобы получить тот же результат.

<Target Name="JoinServers">
  <ItemGroup>
    <Joined Include="%(Identity)">
      <MetaDataA>@(ServerTypeA->'%(MetaDataA)')</MetaDataA>
      <MetaDataB>@(ServerTypeB->'%(MetaDataB)')</MetaDataB>
    </Joined>
  </ItemGroup>

  <Message Text="%(Joined.Identity) Metadata: %(Joined.MetaDataA)%(Joined.MetaDataB)"/>
</Target>
person Aaron Carlson    schedule 23.01.2011
comment
Хороший. Пакетная обработка цели ProcessServerTypeB - это то, чего мне не хватало - person sagie; 24.01.2011