2011-11-30 3 views
0

Ceci est une extension à this question.
Supposons que je crée des éléments de métadonnées d'un autre élément:Copie des métadonnées de l'élément pour le traitement par lots

<ItemGroup> 
    <A> 
     <files>f1;f2;f3;...</files> 
     <x>...</x> 
     <y>...</y> 
     <z>...</z> 
     ... 
    </A> 
    <B Include="%(A.files)"> 
     <x>%(A.x)</x> 
     <y>%(A.y)</y> 
     <z>%(A.z)</z> 
     ... 
    </B> 
</ItemGroup> 

%(A.files) est une liste de fichiers séparés par ;, de sorte que pour chaque Un élément que je crée de nombreux éléments B (un pour chaque fichier).
Mais souvent, lorsque je traite B article, j'ai besoin de métadonnées de l'élément A de l'original. Dans cet exemple, j'ai copié chaque métadonnée manuellement de A à B.

Existe-t-il un moyen de copier toutes les métadonnées de A à B sans spécifier explicitement chacune d'elles?

Répondre

2

Pour autant que je sache, MSBuild ne copie les métadonnées que lorsqu'il existe un mappage un-à-un entre les listes d'éléments d'entrée et de sortie. Dans votre cas, vous commencez avec un élément et vous étendez à de nombreux éléments. Pour contourner ce problème, je suggère d'utiliser batching article:

<?xml version="1.0" encoding="iso-8859-1"?> 
<Project 
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
    ToolsVersion="4.0" 
    DefaultTargets="Print"> 

    <ItemGroup> 
     <A Include="A1"> 
      <files>test.htm;test_sol1.htm</files> 
      <x>a1</x> 
      <y>b1</y> 
      <z>c1</z> 
     </A> 
     <A Include="A2"> 
      <files>test.proj</files> 
      <x>a2</x> 
      <y>b2</y> 
      <z>c2</z> 
     </A> 
    </ItemGroup> 

    <Target Name="ExpandA"> 
     <ItemGroup> 
      <ExpandedA Include="%(A.files)"> 
       <Original>%(Identity)</Original> 
      </ExpandedA> 
     </ItemGroup> 
    </Target> 

    <Target 
     Name="CopyMetadata" 
     Outputs="%(ExpandedA.Identity)" 
     DependsOnTargets="ExpandA"> 

     <PropertyGroup> 
      <ExpandedAIdentity>%(ExpandedA.Identity)</ExpandedAIdentity> 
      <ExpandedAOriginal>%(ExpandedA.Original)</ExpandedAOriginal> 
     </PropertyGroup> 
     <ItemGroup> 
      <ExpandedAMetadata Include="@(A)" Condition=" '%(Identity)' == '$(ExpandedAOriginal)' "> 
       <Expanded>$(ExpandedAIdentity)</Expanded> 
      </ExpandedAMetadata> 
     </ItemGroup> 
    </Target> 

    <Target Name="Print" DependsOnTargets="CopyMetadata"> 
     <ItemGroup> 
      <B Include="@(ExpandedAMetadata->'%(Expanded)')" /> 
     </ItemGroup> 

     <!--Use commas to illustrate that "files" has been expanded--> 
     <Message Text="A: %(A.files)" /> 
     <Message Text="ExpandedA: @(ExpandedA, ',')" /> 
     <Message Text="ExpandedAMetadata: @(ExpandedAMetadata, ',')" /> 
     <Message Text="B: @(B->'%(Identity) x:%(x) y:%(y) z:%(z)', ',')" /> 
    </Target> 
</Project> 

et la sortie de la cible "Imprimer": dans votre question initiale

Print: 
    A: test.htm;test_sol1.htm 
    A: test.proj 
    ExpandedA: test.htm,test_sol1.htm,test.proj 
    ExpandedAMetadata: A1,A1,A2 
    B: test.htm x:a1 y:b1 z:c1,test_sol1.htm x:a1 y:b1 z:c1,test.proj x:a2 y:b2 z:c2 

ExpandedA est similaire à B; c'est la version étendue de A mais sans aucune métadonnée. Ensuite, je lance la cible CopyMetadata une fois pour chaque article en ExpandedA (grâce à la mise en lots des articles). À chaque exécution, l'élément original A est copié dans le groupe d'articles ExpandedAMetadata avec toutes ses métadonnées. Les métadonnées Original sont utilisées pour garantir que l'élément A correct est associé à chaque fichier. Enfin, dans la cible Print, B est construit en utilisant une transformation d'élément, de sorte que toutes les métadonnées de ExpandedAMetadata sont également copiées.

+0

Belle solution, j'aime la façon dont vous avez utilisé le dosage pour le faire. Mais chaque fois que j'ai besoin de copier des métadonnées, j'ai besoin d'écrire une cible "CopyMetadata" supplémentaire pour faire le batching. Je me retrouve à copier des métadonnées trop souvent, j'espérais qu'il y aurait une tâche "CopyMetadata" ou quelque chose de similaire qui me permettrait de le faire sans avoir à écrire une autre cible pour chaque opération de copie. (peut-être une tâche en ligne "CopyMetadata" ...) –

0

Je ne suis pas sûr si je reçois ce dont vous avez besoin, mais vous pouvez copier tout un metedata à B comme dans le answer for related question:

<B Include="@(A)"> 

Il faut copier tous metedata de A à B.

+0

Non, je dois créer un élément B pour chaque fichier dans les métadonnées de fichiers, pas pour chaque élément A comme vous le suggérez. –

2

un peu tard, mais j'aime cette solution mieux:

<B Include="@(A->Metadata('files'))" /> 

Exemple complet:

<?xml version="1.0" encoding="utf-8"?> 
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 

    <ItemGroup> 
     <A Include="A1"> 
      <files>a1_file1.htm;a1_file2.htm</files> 
      <x>a1</x> 
      <y>b1</y> 
      <z>c1</z> 
     </A> 
     <A Include="A2"> 
      <files>a2_file.proj</files> 
      <x>a2</x> 
      <y>b2</y> 
      <z>c2</z> 
     </A> 
     <B Include="@(A->Metadata('files'))" /> 
    </ItemGroup> 

    <Target Name="Build"> 
     <Message Text="A: @(A->'%(Identity) x:%(x) y:%(y) z:%(z) files:%(files)', '&#x0D;&#x0A; ')" /> 
     <Message Text="B: @(B->'%(Identity) x:%(x) y:%(y) z:%(z) files:%(files)', '&#x0D;&#x0A; ')" /> 
    </Target> 

</Project> 

Sortie:

Build: 
    A: A1 x:a1 y:b1 z:c1 files:a1_file1.htm;a1_file2.htm 
    A2 x:a2 y:b2 z:c2 files:a2_file.proj 
    B: a1_file1.htm x:a1 y:b1 z:c1 files:a1_file1.htm;a1_file2.htm 
    a1_file2.htm x:a1 y:b1 z:c1 files:a1_file1.htm;a1_file2.htm 
    a2_file.proj x:a2 y:b2 z:c2 files:a2_file.proj 
Questions connexes