Elementy programu MSBuild

Elementy programu MSBuild są danymi wejściowymi w systemie kompilacji i zazwyczaj reprezentują pliki (pliki są określone w atrybucie Include ). Elementy są pogrupowane w typy elementów na podstawie ich nazw elementów. Typy elementów są nazwanymi listami elementów, których można użyć jako parametrów dla zadań podrzędnych. Zadania używają wartości elementów do wykonania kroków procesu kompilacji.

Ponieważ elementy są nazwane przez typ elementu, do którego należą, terminy "item" i "item value" mogą być używane zamiennie.

Tworzenie elementów w pliku projektu

Elementy w pliku projektu są deklarowane jako elementy podrzędne elementu ItemGroup . Prawidłowe nazwy elementów zaczynają się od wielkich lub małych liter lub podkreślenia (_); prawidłowe kolejne znaki zawierają znaki alfanumeryczne (litery lub cyfry), podkreślenie i łącznik (-). Nazwa elementu podrzędnego jest typem elementu. Atrybut Include elementu określa elementy (pliki), które mają być dołączone do tego typu elementu. Na przykład poniższy kod XML tworzy typ elementu o nazwie Compile, który zawiera dwa pliki.

<ItemGroup>
    <Compile Include = "file1.cs"/>
    <Compile Include = "file2.cs"/>
</ItemGroup>

Element file2.cs nie zastępuje elementu file1.cs. Zamiast tego nazwa pliku jest dołączana do listy wartości typu Compile elementu.

Poniższy kod XML tworzy ten sam typ elementu, deklarując oba pliki w jednym Include atrybucie. Zwróć uwagę, że nazwy plików są oddzielone średnikiem.

<ItemGroup>
    <Compile Include = "file1.cs;file2.cs"/>
</ItemGroup>

Atrybut Include jest ścieżką interpretowaną względem folderu pliku projektu, $(MSBuildProjectPath)nawet jeśli element znajduje się w zaimportowanym pliku, takim jak .targets plik.

Tworzenie elementów podczas wykonywania

Elementy, które znajdują się poza elementami docelowymi , są przypisywane wartości w fazie oceny kompilacji. Podczas kolejnej fazy wykonywania elementy można tworzyć lub modyfikować w następujący sposób:

  • Każde zadanie może emitować element. Aby emitować element, element Task musi mieć podrzędny element Wyjściowy , który ma ItemName atrybut.

  • Zadanie CreateItem może emitować element. Takie użycie jest przestarzałe.

  • Target elementy mogą zawierać elementy ItemGroup , które mogą zawierać elementy elementu.

Odwołania do elementów w pliku projektu

Aby odwołać się do typów elementów w pliku projektu, należy użyć składni @(ItemType). Możesz na przykład odwołać się do typu elementu w poprzednim przykładzie przy użyciu polecenia @(Compile). Korzystając z tej składni, można przekazać elementy do zadań, określając typ elementu jako parametr tego zadania. Aby uzyskać więcej informacji, zobacz How to: Select the files to build (Instrukcje: wybieranie plików do skompilowania).

Domyślnie elementy typu elementu są oddzielone średnikami (;) po rozwinięciu. Składnia @(ItemType, 'separator') służy do określania separatora innego niż domyślny. Aby uzyskać więcej informacji, zobacz How to: Display an item list separated with commas (Instrukcje: wyświetlanie listy elementów rozdzielonych przecinkami).

Używanie symboli wieloznacznych do określania elementów

Można użyć **znaków , *i ? symboli wieloznacznych, aby określić grupę plików jako dane wejściowe dla kompilacji, zamiast wyświetlać poszczególne pliki oddzielnie.

  • Symbol ? wieloznaczny pasuje do pojedynczego znaku.
  • Symbol * wieloznaczny pasuje do zera lub większej liczby znaków.
  • Sekwencja ** znaków wieloznacznych jest zgodna ze ścieżką częściową.

Można na przykład określić wszystkie .cs pliki w katalogu zawierającym plik projektu, używając następującego elementu w pliku projektu.

<CSFile Include="*.cs"/>

Poniższy element wybiera wszystkie .vb pliki na D: dysku:

<VBFile Include="D:/**/*.vb"/>

Jeśli chcesz uwzględnić literał * lub ? znaki w elemencie bez rozszerzenia symboli wieloznacznych, musisz zawrzeć znaki wieloznaczne.

Aby uzyskać więcej informacji na temat symboli wieloznacznych, zobacz Instrukcje: wybieranie plików do skompilowania.

Używanie atrybutu Exclude

Elementy elementu mogą zawierać Exclude atrybut, który wyklucza określone elementy (pliki) z typu elementu. Atrybut Exclude jest zwykle używany razem z symbolami wieloznacznymi. Na przykład poniższy kod XML dodaje każdy plik .cs w katalogu do CSFile typu elementu, z wyjątkiem pliku DoNotBuild.cs .

<ItemGroup>
    <CSFile  Include="*.cs"  Exclude="DoNotBuild.cs"/>
</ItemGroup>

Atrybut Exclude ma wpływ tylko na elementy, które są dodawane przez Include atrybut w elemencie elementu, który zawiera je oba. Poniższy przykład nie wyklucza Form1.cs pliku, który został dodany w poprzednim elemencie elementu.

<Compile Include="*.cs" />
<Compile Include="*.res" Exclude="Form1.cs">

Aby uzyskać więcej informacji, zobacz How to: Exclude files from the build (Instrukcje: wykluczanie plików z kompilacji).

Metadane elementu

Elementy mogą zawierać metadane oprócz informacji w atrybutach Include i Exclude . Te metadane mogą być używane przez zadania, które wymagają dodatkowych informacji o elementach lub zadaniach wsadowych i docelowych. Aby uzyskać więcej informacji, zobacz Batching (Przetwarzanie wsadowe).

Metadane to kolekcja par klucz-wartość zadeklarowanych w pliku projektu jako elementy podrzędne elementu elementu. Nazwa elementu podrzędnego to nazwa metadanych, a wartość elementu podrzędnego jest wartością metadanych.

Metadane są skojarzone z elementem elementu, który go zawiera. Na przykład poniższy kod XML dodaje Culture metadane, które mają wartość Fr zarówno do one.cs , jak i two.cs elementów CSFile typu elementu.

<ItemGroup>
    <CSFile Include="one.cs;two.cs">
        <Culture>Fr</Culture>
    </CSFile>
</ItemGroup>

Element może mieć zero lub więcej wartości metadanych. Wartości metadanych można zmieniać w dowolnym momencie. Jeśli ustawisz metadane na wartość pustą, skutecznie usuniesz je z kompilacji.

Odwołania do metadanych elementu w pliku projektu

Metadane elementów można odwoływać się do całego pliku projektu przy użyciu składni %(ItemMetadataName). Jeśli istnieje niejednoznaczność, możesz zakwalifikować odwołanie przy użyciu nazwy typu elementu. Można na przykład określić wartość %(ItemType.ItemMetaDataName). W poniższym przykładzie użyto Display metadanych do wsadu zadania Message . Aby uzyskać więcej informacji na temat używania metadanych elementu do dzielenia na partie, zobacz Metadane elementu w partiach zadań.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <Stuff Include="One.cs" >
            <Display>false</Display>
        </Stuff>
        <Stuff Include="Two.cs">
            <Display>true</Display>
        </Stuff>
    </ItemGroup>
    <Target Name="Batching">
        <Message Text="@(Stuff)" Condition=" '%(Display)' == 'true' "/>
    </Target>
</Project>

Dobrze znane metadane elementu

Po dodaniu elementu do typu elementu ten element ma przypisane dobrze znane metadane. Na przykład wszystkie elementy mają dobrze znane metadane %(Filename), których wartością jest nazwa pliku elementu (bez rozszerzenia). Aby uzyskać więcej informacji, zobacz Dobrze znane metadane elementu.

Przekształcanie typów elementów przy użyciu metadanych

Listy elementów można przekształcić w nowe listy elementów przy użyciu metadanych. Na przykład można przekształcić typ CppFiles elementu, który zawiera elementy reprezentujące .cpp pliki na odpowiadającą listę .obj plików przy użyciu wyrażenia @(CppFiles -> '%(Filename).obj').

Poniższy kod tworzy CultureResource typ elementu zawierający kopie wszystkich EmbeddedResource elementów z metadanymi Culture . Wartość Culture metadanych staje się wartością nowych metadanych CultureResource.TargetDirectory.

<Target Name="ProcessCultureResources">
    <ItemGroup>
        <CultureResource Include="@(EmbeddedResource)"
            Condition="'%(EmbeddedResource.Culture)' != ''">
            <TargetDirectory>%(EmbeddedResource.Culture) </TargetDirectory>
        </CultureResource>
    </ItemGroup>
</Target>

Aby uzyskać więcej operacji na elementach, zobacz Funkcje elementów MSBuild i Przekształcenia.

Definicje elementów

Domyślne metadane można dodać do dowolnego typu elementu przy użyciu elementu ItemDefinitionGroup. Podobnie jak dobrze znane metadane, domyślne metadane są skojarzone ze wszystkimi elementami określonego typu elementu. Możesz jawnie zastąpić domyślne metadane w definicji elementu. Na przykład poniższy kod XML zawiera Compile elementy one.cs i three.cs metadanych BuildDay o wartości "Poniedziałek". Kod daje element two.cs metadanych BuildDay z wartością "wtorek".

<ItemDefinitionGroup>
    <Compile>
        <BuildDay>Monday</BuildDay>
    </Compile>
</ItemDefinitionGroup>
<ItemGroup>
    <Compile Include="one.cs;three.cs" />
    <Compile Include="two.cs">
        <BuildDay>Tuesday</BuildDay>
    </Compile>
</ItemGroup>

Aby uzyskać więcej informacji, zobacz Definicje elementów.

Atrybuty elementów w grupie elementów docelowych

Target elementy mogą zawierać elementy ItemGroup , które mogą zawierać elementy elementu. Atrybuty w tej sekcji są prawidłowe po określeniu elementu w obiekcie ItemGroup w Targetobiekcie .

Usuń atrybut

Atrybut Remove usuwa określone elementy (pliki) z typu elementu. Ten atrybut został wprowadzony w programie .NET Framework 3.5 (tylko wewnątrz elementów docelowych). Obiekty docelowe wewnątrz i na zewnątrz są obsługiwane począwszy od programu MSBuild 15.0.

Poniższy przykład usuwa każdy .config plik z Compile typu elementu.

<Target>
    <ItemGroup>
        <Compile Remove="*.config"/>
    </ItemGroup>
</Target>

MatchOnMetadata, atrybut

Atrybut MatchOnMetadata ma zastosowanie tylko do atrybutów odwołujących się do Remove innych elementów (na przykład Remove="@(Compile);@(Content)") i instruuje Remove operację, aby dopasować elementy na podstawie wartości określonych nazw metadanych, zamiast dopasowywać na podstawie wartości elementu.

Reguła dopasowania dla B Remove="@(A)" MatchOnMetadata="M"elementu : usuń wszystkie elementy z B metadanych, które mają metadane M, których wartość V metadanych pasuje M do dowolnego elementu z A metadanych M wartości V.

<Project>
  <ItemGroup>
    <A Include='a1' M1='1' M2='a' M3="e"/>
    <A Include='b1' M1='2' M2='x' M3="f"/>
    <A Include='c1' M1='3' M2='y' M3="g"/>
    <A Include='d1' M1='4' M2='b' M3="h"/>

    <B Include='a2' M1='x' m2='c' M3="m"/>
    <B Include='b2' M1='2' m2='x' M3="n"/>
    <B Include='c2' M1='2' m2='x' M3="o"/>
    <B Include='d2' M1='3' m2='y' M3="p"/>
    <B Include='e2' M1='3' m2='Y' M3="p"/>
    <B Include='f2' M1='4'        M3="r"/>
    <B Include='g2'               M3="s"/>

    <B Remove='@(A)' MatchOnMetadata='M1;M2'/>
  </ItemGroup>

  <Target Name="PrintEvaluation">
    <Message Text="%(B.Identity) M1='%(B.M1)' M2='%(B.M2)' M3='%(B.M3)'" />
  </Target>
</Project>

W tym przykładzie wartości b2elementów , c2i d2 są usuwane z elementu B , ponieważ:

  • b2i c2 z meczu przeciwko b1BA z na i M1=2M2=x
  • d2 z B dopasowań względem c1 z A wł. M1=3 i M2=y

Zadanie Message zwraca następujące dane wyjściowe:

  a2 M1='x' M2='c' M3='m'
  e2 M1='3' M2='Y' M3='p'
  f2 M1='4' M2='' M3='r'
  g2 M1='' M2='' M3='s'

Przykładowe użycie z programu MatchOnMetadataMSBuild:

      <_TransitiveItemsToCopyToOutputDirectory Remove="@(_ThisProjectItemsToCopyToOutputDirectory)" MatchOnMetadata="TargetPath" MatchOnMetadataOptions="PathLike" />

Ten wiersz usuwa elementy z _TransitiveItemsToCopyToOutputDirectory tych samych TargetPath wartości metadanych z elementów w _ThisProjectItemsToCopyToOutputDirectory

MatchOnMetadataOptions, atrybut

Określa strategię dopasowywania ciągów używaną przez MatchOnMetadata do dopasowywania wartości metadanych między elementami (nazwy metadanych są zawsze dopasowane bez uwzględniania wielkości liter). Możliwe wartości to CaseSensitive, CaseInsensitivelub PathLike. Domyślna wartość to CaseSensitive.

PathLike stosuje normalizację z obsługą ścieżki do wartości, takich jak normalizacja orientacji ukośnika, ignorując końcowe ukośniki, eliminując . i .., i tworząc wszystkie ścieżki względne bezwzględne względem bieżącego katalogu.

KeepMetadata, atrybut

Jeśli element jest generowany w elemencie docelowym, element elementu może zawierać KeepMetadata atrybut . Jeśli ten atrybut zostanie określony, tylko metadane określone w rozdzielanej średnikami liście nazw zostaną przeniesione z elementu źródłowego do elementu docelowego. Pusta wartość tego atrybutu jest równoważna nieokreśliniu go. Atrybut KeepMetadata został wprowadzony w programie .NET Framework 4.5.

W poniższym przykładzie pokazano, jak używać atrybutu KeepMetadata .

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0">

    <ItemGroup>
        <FirstItem Include="rhinoceros">
            <Class>mammal</Class>
            <Size>large</Size>
        </FirstItem>

    </ItemGroup>
    <Target Name="MyTarget">
        <ItemGroup>
            <SecondItem Include="@(FirstItem)" KeepMetadata="Class" />
        </ItemGroup>

        <Message Text="FirstItem: %(FirstItem.Identity)" />
        <Message Text="  Class: %(FirstItem.Class)" />
        <Message Text="  Size:  %(FirstItem.Size)"  />

        <Message Text="SecondItem: %(SecondItem.Identity)" />
        <Message Text="  Class: %(SecondItem.Class)" />
        <Message Text="  Size:  %(SecondItem.Size)"  />
    </Target>
</Project>

<!--
Output:
  FirstItem: rhinoceros
    Class: mammal
    Size:  large
  SecondItem: rhinoceros
    Class: mammal
    Size:
-->

RemoveMetadata, atrybut

Jeśli element jest generowany w elemencie docelowym, element elementu może zawierać RemoveMetadata atrybut . Jeśli ten atrybut zostanie określony, wszystkie metadane są przesyłane z elementu źródłowego do elementu docelowego z wyjątkiem metadanych, których nazwy znajdują się na rozdzielanej średnikami liście nazw. Pusta wartość tego atrybutu jest równoważna nieokreśliniu go. Atrybut RemoveMetadata został wprowadzony w programie .NET Framework 4.5.

W poniższym przykładzie pokazano, jak używać atrybutu RemoveMetadata .

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <MetadataToRemove>Size;Material</MetadataToRemove>
    </PropertyGroup>

    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <Item2 Include="@(Item1)" RemoveMetadata="$(MetadataToRemove)" />
        </ItemGroup>

        <Message Text="Item1: %(Item1.Identity)" />
        <Message Text="  Size:     %(Item1.Size)" />
        <Message Text="  Color:    %(Item1.Color)" />
        <Message Text="  Material: %(Item1.Material)" />
        <Message Text="Item2: %(Item2.Identity)" />
        <Message Text="  Size:     %(Item2.Size)" />
        <Message Text="  Color:    %(Item2.Color)" />
        <Message Text="  Material: %(Item2.Material)" />
    </Target>
</Project>

<!--
Output:
  Item1: stapler
    Size:     medium
    Color:    black
    Material: plastic
  Item2: stapler
    Size:
    Color:    black
    Material:
-->

Aby uzyskać więcej operacji na elementach, zobacz Funkcje elementów MSBuild.

KeepDuplicates, atrybut

Jeśli element jest generowany w elemencie docelowym, element elementu może zawierać KeepDuplicates atrybut . KeepDuplicates jest atrybutem określającym Boolean , czy element powinien zostać dodany do grupy docelowej, jeśli element jest dokładnym duplikatem istniejącego elementu.

Jeśli element źródłowy i docelowy mają tę samą Include wartość, ale różne metadane, element zostanie dodany, nawet jeśli KeepDuplicates jest ustawiony na falsewartość . Pusta wartość tego atrybutu jest równoważna nieokreśliniu go. Atrybut KeepDuplicates został wprowadzony w programie .NET Framework 4.5.

W poniższym przykładzie pokazano, jak używać atrybutu KeepDuplicates .

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <ItemGroup>
        <Item1 Include="hourglass;boomerang" />
        <Item2 Include="hourglass;boomerang" />
    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <Item1 Include="hourglass" KeepDuplicates="false" />
            <Item2 Include="hourglass" />
        </ItemGroup>

        <Message Text="Item1: @(Item1)" />
        <Message Text="  %(Item1.Identity)  Count: @(Item1->Count())" />
        <Message Text="Item2: @(Item2)" />
        <Message Text="  %(Item2.Identity)  Count: @(Item2->Count())" />
    </Target>
</Project>

<!--
Output:
  Item1: hourglass;boomerang
    hourglass  Count: 1
    boomerang  Count: 1
  Item2: hourglass;boomerang;hourglass
    hourglass  Count: 2
    boomerang  Count: 1
-->

KeepDuplicates Ponieważ atrybut uwzględnia metadane elementów oprócz wartości elementu, ważne jest, aby wiedzieć, co dzieje się z metadanymi. Na przykład zobacz Wykrywanie duplikatów podczas korzystania z funkcji Elementu metadanych.

Aktualizowanie metadanych elementów w grupie elementów poza elementem docelowym

Elementy spoza obiektów docelowych mogą mieć istniejące metadane zaktualizowane za pośrednictwem atrybutu Update . Ten atrybut nie jest dostępny dla elementów docelowych.

<Project>
    <PropertyGroup>
        <MetadataToUpdate>pencil</MetadataToUpdate>
    </PropertyGroup>

    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Color>red</Color>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="notebook">
            <Size>SMALL</Size>
            <Color>YELLOW</Color>
        </Item2>

        <!-- Metadata can be expressed either as attributes or as elements -->
        <Item1 Update="$(MetadataToUpdate);stapler;er*r;@(Item2)" Price="10" Material="">
            <Color>RED</Color>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: medium
    Color: RED
    Material:
    Price: 10
Item1: pencil
    Size: small
    Color: RED
    Material:
    Price: 10
Item1: eraser
    Size:
    Color: RED
    Material:
    Price: 10
Item1: notebook
    Size: large
    Color: RED
    Material:
    Price: 10
-->

W programie MSBuild w wersji 16.6 lub nowszej Update atrybut obsługuje kwalifikowane odwołania do metadanych w celu ułatwienia importowania metadanych z co najmniej dwóch elementów.

<Project>
    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Size>small</Size>
            <Color>red</Color>
            <Material>gum</Material>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="pencil">
            <Size>MEDIUM</Size>
            <Color>RED</Color>
            <Material>PLASTIC</Material>
            <Price>10</Price>
        </Item2>

        <Item3 Include="notebook">
            <Size>SMALL</Size>
            <Color>BLUE</Color>
            <Price>20</Price>
        </Item3>

        <!-- Metadata can be expressed either as attributes or as elements -->
        <Item1 Update="@(Item2);er*r;@(Item3)" Size="%(Size)" Color="%(Item2.Color)" Price="%(Item3.Price)" Model="2020">
            <Material Condition="'%(Item2.Material)' != ''">Premium %(Item2.Material)</Material>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)
    Model: %(Item1.Model)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: medium
    Color: black
    Material: plastic
    Price:
    Model:
Item1: pencil
    Size: small
    Color: RED
    Material: Premium PLASTIC
    Price:
    Model: 2020
Item1: eraser
    Size: small
    Color:
    Material: gum
    Price:
    Model: 2020
Item1: notebook
    Size: large
    Color:
    Material: paper
    Price: 20
    Model: 2020
-->

Uwagi:

  • Metadane niekwalifikowane (%(MetadataName)) wiążą się z aktualizowanym typem elementu (Item1 w powyższym przykładzie). Kwalifikowane metadane (%(Item2.Color)) wiążą się wewnątrz zestawu przechwyconych pasujących typów elementów z wyrażenia Update.
  • Jeśli element pasuje wiele razy w obrębie i między wieloma przywołynymi elementami:
    • Ostatnie wystąpienie każdego przywoływanego typu elementu jest przechwytywane (więc jeden przechwycony element na typ elementu).
    • Jest to zgodne z zachowaniem dzielenia elementu zadania na partie w ramach elementów docelowych.
  • Gdzie można umieścić odwołania %():
    • Metadane
    • Warunki metadanych
  • Dopasowywanie nazw metadanych jest bez uwzględniania wielkości liter.

Aktualizowanie metadanych elementów w grupie elementów docelowych

Metadane można również modyfikować wewnątrz obiektów docelowych za pomocą mniej wyrazistej składni niż Update:

<Project>
    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Size>small</Size>
            <Color>red</Color>
            <Material>gum</Material>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="pencil">
            <Size>MEDIUM</Size>
            <Color>RED</Color>
            <Material>PLASTIC</Material>
            <Price>10</Price>
        </Item2>

        <Item2 Include="ruler">
            <Color>GREEN</Color>
        </Item2>

    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <!-- Metadata can be expressed either as attributes or as elements -->
            <Item1 Size="GIGANTIC" Color="%(Item2.Color)">
                <Material Condition="'%(Item2.Material)' != ''">Premium %(Item2.Material)</Material>
            </Item1>
        </ItemGroup>

        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)
    Model: %(Item1.Model)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: pencil
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: eraser
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: notebook
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
-->