ackh
ackh

Reputation: 2052

How to create or update the value of an element using XmlPoke

In an MSBuild target, I need to set the value of an XML element to a specific value. If that element does not exist I need to create it. I'm trying to achieve this using MSBuild's XmlPoke task but it only works if the element exists already. Here's an example:

XML content to update:

<?xml version="1.0" encoding="utf-8"?>
<manifest>
  <metadata>
    <name>whatever</name>
    <version>1.2.3.4</version>
  </metadata>
</manifest>

Using XmlPoke as shown below, I can successfully set the value of the version element:

<XmlPoke
  XmlInputPath="$(XmlFilePath)"
  Query="/manifest/metadata/version"
  Value="4.3.2.1" />

The result of that looks as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest>
  <metadata>
    <name>whatever</name>
    <version>4.3.2.1</version>
  </metadata>
</manifest>

However, if the input is missing the version element, as shown below, the XmlPoke task just doesn't do anything:

<?xml version="1.0" encoding="utf-8"?>
<manifest>
  <metadata>
    <name>whatever</name>
  </metadata>
</manifest>

How can I create the version element and set it to 4.3.2.1 if it does not exist or just set it to 4.3.2.1 if it does exist using MSBuild standard functionality?


Edit:

The accepted answer with combining both XmlPeek and XmlPoke works. Based on that answer, here's the code that inserts or updates the value:

<XmlPeek
   XmlInputPath="$(XmlFilePath)"
   Query="/manifest/metadata/version">
   <Output
      TaskParameter="Result"
      ItemName="VersionEntry" />
</XmlPeek>
<XmlPoke
   Condition="'@(VersionEntry)' != ''"
   XmlInputPath="$(XmlFilePath)"
   Query="/manifest/metadata/version"
   Value="4.3.2.1" />
<XmlPoke
   Condition="'@(VersionEntry)' == ''"
   XmlInputPath="$(XmlFilePath)"
   Query="/manifest/metadata"
   Value="&lt;Name&gt;whatever&lt;/Name&gt;&lt;Version&gt;4.3.2.1&lt;/Version&gt;" />

Upvotes: 2

Views: 667

Answers (1)

Jonathan Dodds
Jonathan Dodds

Reputation: 5163

XmlPoke uses the specified XPath, the Query, to find matching nodes. If it finds a node, it replaces the InnerXml with the specified Value. It will do this for each match. If there are no matches, XmlPoke does nothing.

An approach using standard MSBuild functionality:

Use XmlPeek to test for /manifest/metadata/version.

If version exists, then use XmlPoke to update.

If version does not exist:

  1. Use XmlPeek to get the contents of /manifest/metadata.
  2. Create a replacement value consisting of the existing contents of metadata with <version>$(ver)</version> appended.
  3. Use XmlPoke to update /manifest/metadata.

If that seems cumbersome, you could write an inline task that 'upserts' the version.

Upvotes: 3

Related Questions