> For the complete documentation index, see [llms.txt](https://til.cazzulino.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://til.cazzulino.com/msbuild/write-entire-xml-fragments-in-msbuild-with-xmlpoke.md).

# Write entire XML fragments in MSBuild with XmlPoke

I recently needed to write an entire project file via a targets (weird, I know). I was dreading all the crazy angle brackets escaping as `&lt;` and `&gt;` when I decided to check the [latest official docs on XmlPoke](https://docs.microsoft.com/en-us/visualstudio/msbuild/xmlpoke-task?view=vs-2019) to refresh the parameters and format. To my surprise, I found this example:

```markup
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Namespace>
        <Namespace Prefix="dn" Uri="http://schemas.microsoft.com/appx/manifest/foundation/windows10" />
        <Namespace Prefix="mp" Uri="http://schemas.microsoft.com/appx/2014/phone/manifest" />
        <Namespace Prefix="uap" Uri="http://schemas.microsoft.com/appx/manifest/uap/windows10" />
    </Namespace>
</PropertyGroup>

<Target Name="Poke">
  <XmlPoke
    XmlInputPath="Sample.xml"
    Value="MyId"
    Query="/dn:Package/mp:PhoneIdentity/@PhoneProductId"
    Namespaces="$(Namespace)"/>
</Target>
</Project>
```

Notice how the `$(Namespace)` property has **beautiful** XML inside. Which only makes sense, since, there had to be **some** advantage in MSBuild being XML, right? So I figured, if the namespaces can be a full nested XML element, could the `Value` be too? And the answer was a [resounding YEAHHH](https://github.com/kzu/SmallSharp/blob/main/src/SmallSharp/SmallSharp.targets#L88-L100):

```markup
  <PropertyGroup>
    <UserPropertyGroup>
      <PropertyGroup>
        <ActiveDebugProfile>$(StartupFile)</ActiveDebugProfile>
      </PropertyGroup>
    </UserPropertyGroup>    
  </PropertyGroup>

  <XmlPoke XmlInputPath="$(MSBuildProjectFullPath).user"
           Value="$(UserPropertyGroup)"
           Query="/msb:Project"
           Namespaces="$(UserProjectNamespace)"/>
```

That writes an entire `<PropertyGroup>` element into a .user project file!

For the attentive reader: you'd think I made a mistake, since, in XML-land, elements inherit the XML namespace of their parent element. Seems like the XML namespace management in XmlPoke is a bit on the loose side of things: the above snippets are in a .targets file without any xmlns (it's an SDK-style `<Project>` without namespace, to keep it clean. Yet, the property group is added without messing up the namespace:

```markup
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ActiveDebugProfile>Program.cs</ActiveDebugProfile>
  </PropertyGroup>
</Project>
```

If it had inserted it without a namespace, per the XML spec, it should have added an `xmlns=""` to clear the parent Project node namespace. But alas, it didn't, and in this particular case, it makes it way more convenient this way :).

I'm using this in [SmallSharp](https://github.com/kzu/SmallSharp) to initialize the .user project options properly with the right startup file for multi-startup top-level statements scripts in a single project :).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://til.cazzulino.com/msbuild/write-entire-xml-fragments-in-msbuild-with-xmlpoke.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
