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 Target
obiekcie .
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 b2
elementów , c2
i d2
są usuwane z elementu B
, ponieważ:
b2
ic2
z meczu przeciwkob1
B
A
z na iM1=2
M2=x
d2
zB
dopasowań względemc1
zA
wł.M1=3
iM2=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 MatchOnMetadata
MSBuild:
<_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
, CaseInsensitive
lub 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 false
wartość . 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:
-->