Reputation: 1275
I'd like to create a XML file within a MSBuild task.
I have a list of files:
<CreateItem Include="$(TestsAssembliesOutputDir)\Emidee.*.Tests.dll">
<Output ItemName="TestsAssemblies" TaskParameter="Include" />
</CreateItem>
I'd like to create a XML which would look like:
<?xml version="1.0" encoding="utf-8"?>
<xunit>
<assemblies>
<assembly filename="PATH OF FILE #1" shadow-copy="true" />
<assembly filename="PATH OF FILE #2" shadow-copy="true" />
</assemblies>
</xunit>
How can I achieve that?
Thanks in advance
Mike
Upvotes: 21
Views: 12357
Reputation: 380
New version of Brian solution with the "initial < ? xml line", without the "Text" and without encoding quotes:
<Target Name="CreateXml">
<ItemGroup>
<TestAssembly Include="$(TestsAssembliesOutputDir)\Emidee.*.Tests.dll" />
<Line Include='<%3Fxml version="1.0" encoding="utf-8"%3F>' />
<Line Include='<xunit>' />
<Line Include='<assemblies>' />
<Line Include='<assembly filename="%(TestAssembly.Identity)" shadow-copy="true" />' />
<Line Include='</assemblies>' />
<Line Include='</xunit>' />
</ItemGroup>
<WriteLinesToFile
File="out.xml"
Lines="@(Line)"
Overwrite="true"
/>
</Target>
Upvotes: 1
Reputation: 29528
One option would be to use an inline task. This allows you to write arbitrary C# code to generate the Xml, which might be easier (or might be harder) than alternative solutions. Here is an example that I was using to hack together a NuGet nuspec file in my build.
...
<UsingTask
TaskName="CreateNugetPackage"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"
>
<ParameterGroup>
<ProjectName ParameterType="System.String" Required="true" />
<Version ParameterType="System.String" Required="true" />
<BaseFolder ParameterType="System.String" Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<OutputFile ParameterType="Microsoft.Build.Framework.ITaskItem" Required="true" />
</ParameterGroup>
<Task>
<Reference Include="System.Xml" />
<Using Namespace="System" />
<Using Namespace="System.Xml" />
<Code Type="Fragment" Language="cs">
<![CDATA[
var root = Path.GetFullPath(BaseFolder);
using (var w = XmlWriter.Create(OutputFile.ItemSpec)) {
var ns = "http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd";
w.WriteStartElement("package", ns);
w.WriteStartElement("metadata");
w.WriteStartElement("id");
w.WriteValue(ProjectName);
w.WriteEndElement();
w.WriteStartElement("version");
w.WriteValue(Version);
w.WriteEndElement();
w.WriteStartElement("description");
w.WriteValue("Test");
w.WriteEndElement();
w.WriteStartElement("authors");
w.WriteValue("Test");
w.WriteEndElement();
w.WriteEndElement();
w.WriteStartElement("files");
foreach(var file in Files) {
w.WriteStartElement("file");
var inFile = file.ItemSpec;
inFile = inFile.Replace(root, "");
w.WriteAttributeString("src", inFile);
w.WriteAttributeString("target", inFile);
w.WriteEndElement();
}
w.WriteEndElement();
w.WriteEndElement();
}
]]>
</Code>
</Task>
</UsingTask>
<Target Name="CreateNuspec" BeforeTargets="BuildNugetPackage">
<CreateNugetPackage
Files="@(Artifacts)"
OutputFile="$(NugetPackageSpec)"
ProjectName="$(ProjectName)"
BaseFolder="$(ArtifactRoot)"
Version="$(Version)"
/>
</Target>
...
Some relevant documentation:
Upvotes: 2
Reputation: 9938
Quick and dirty...
<Target Name="CreateXml">
<ItemGroup>
<TestAssembly Include="$(TestsAssembliesOutputDir)\Emidee.*.Tests.dll" />
<Line Include="line01"><Text><xunit></Text></Line>
<Line Include="line02"><Text><assemblies></Text></Line>
<Line Include="line03"><Text><assembly filename="%(TestAssembly.Identity)" shadow-copy="true" /></Text></Line>
<Line Include="line04"><Text></assemblies></Text></Line>
<Line Include="line05"><Text></xunit></Text></Line>
<LineText Include="%(Line.Text)" />
</ItemGroup>
<WriteLinesToFile
File="out.xml"
Lines="@(LineText)"
Overwrite="true"
/>
</Target>
Left as an exercise for you
You could also use the following in WriteLinesToFile and omit the synthesized @(LineText)
Lines="@(Line->'%(Text)')"
Upvotes: 32