Перекрестное соединение ItemGroups в MSBuild

Учитывая что-то вроде этого..

 <?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>

Я бы хотел, чтобы вывод был примерно таким.. (с учетом двух файлов one.config и two.config)

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

(порядок не важен, просто полное декартово произведение двух ItemGroups)


person Dog Ears    schedule 09.04.2013    source источник


Ответы (2)


Это кажется аккуратным решением:

<?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>
person Dog Ears    schedule 10.04.2013
comment
Это не объединит метаданные элемента так, как вы хотели, или не даст желаемого результата. Это просто выведет DB1 в одной строке и DB2 в другой строке. Предложенный мной ответ обеспечивает гибкость при объединении метаданных и дает результаты, о которых вы просили. - person Michael; 10.04.2013
comment
А, я вижу, что пошло не так, когда я пытался локально: когда я пробовал, я думал, что путь к моим образцам конфигураций был неправильным. В вашем файле указан полный путь к конфигурации, а не только имя/расширение файла конфигурации. - person Michael; 10.04.2013
comment
Ха-ха-ха, в конце концов, это ваш сжатый ответ. ;-) - person Michael; 10.04.2013

Есть способ сделать это с минимальными изменениями в существующем примере кода. Вы можете объединить метаданные из ConfigFiles элементов и DatabaseConfig элементов в новый "комбинированный ", а затем выведите этот "комбинированный" элемент.

Чтобы объединить метаданные, используйте целевую пакетную обработку с пакетной целью, запускаемой один раз для каждого элемента DatabaseConfig. Затем вы можете вызвать другую цель для вывода комбинированных метаданных, чтобы получить описанный вами вывод. Взгляните на мое расширение вашего примера кода, чтобы увидеть, как все это будет выполнено:

<?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>

Что происходит в образце:

  1. Цель test теперь просто служит способом вызова двух других целей для выполнения работы: test_setup и test_output.
  2. Цель test_setup группируется и создает новые элементы CombinedOutput.
  3. Цель test_output вызывается после test_setup для вывода метаданных CombinedOutput элементов.

Выход из test_output:

one.config DB1
two.config DB1
one.config DB2
two.config DB2
person Michael    schedule 10.04.2013
comment
Я должен быть более явным, мне нужно, чтобы две переменные были отдельными. Сообщение предназначено только для проверки, фактические переменные будут использоваться на этапе XmlUpdate. - person Dog Ears; 10.04.2013
comment
Ну, да, это было бы хорошо знать заранее. ;-) Мое предложение отвечает вашим первоначальным критериям, но не фокусируется на разделении этих переменных. - person Michael; 10.04.2013