With the rules engine you can't directly add a node to an XML document in a rules action. On the other time you often would like to do that. No worries, you can call a helper class to do the work for you. Here is an example helper class from John Rummell <welcome back> that does the trick. Nothing particularly revolutionary in the code but it will save you some time I'm sure.

using System;

using System.Xml;

using Microsoft.RuleEngine;

namespace XMLHelpers

{

/// <summary>

/// Class used to add nodes and/or attributes to a TypedXmlDocument

///

/// Using the example:

/// <root>

/// <a>

/// </a>

/// </root>

///

/// AddNode(doc, "/root/a", "b") or AddNodeIfNotThere(doc, "/root/a", "b") will result in:

/// <root>

/// <a>

/// <b />

/// </a>

/// </root>

///

/// AddAttribute(doc, "//a", "name", "value") will result in:

/// <root>

/// <a name="value">

/// </a>

/// </root>

///

/// The code does not create intermediate nodes (e.g. can't create a "c" inside "b"

/// if "b" doesn't exist. As a result, you need to sequence the calls:

/// AddNode(doc, "/root/a", "b");

/// AddNode(doc, "/root/a/b", "c");

/// Note that if "b" already exists, a second "b" node will be created. Use AddNodeIfNotThere

/// to create the node "b" if it doesn't already exist, but leave it alone if it is.

/// </summary>

public class XmlCreateNodes

{

/// <summary>

/// Add an attribute with a specified name and value into the node selected by the XPath

/// </summary>

/// <param name="txd">RuleEngine wrapper for an XmlDocument (or some part of it)</param>

/// <param name="xPath">XPath that must select a node (null or "" to use current node)</param>

/// <param name="attributeName">Attribute name</param>

/// <param name="attributeValue">Attribute value</param>

public void AddAttribute(TypedXmlDocument txd, string xPath, string attributeName, string attributeValue)

{

// can we find the XPath indicated?

// we need an XmlElement in order to set the attribute, not the usual XmlNode

// if the result is not an XmlElement, we don't work

XmlElement node = LocateXPath(txd, xPath) as XmlElement;

// if we found a matching node, add the attribute

if (null != node)

{

node.SetAttribute(attributeName, attributeValue);

}

}

/// <summary>

/// Add an new node with a specified name and namespace into the node selected by the XPath

/// </summary>

/// <param name="txd">RuleEngine wrapper for an XmlDocument (or some part of it)</param>

/// <param name="xPath">XPath that must select a node (null or "" to use current node)</param>

/// <param name="nodeName">Name for the new node</param>

/// <param name="nodeNamespace">Namespace for the new node</param>

public void AddNode(TypedXmlDocument txd, string xPath, string nodeName, string nodeNamespace)

{

// can we find the XPath indicated?

XmlNode node = LocateXPath(txd, xPath);

if (null == node) return;

// determine the root node for the document

// if the XPath selects the TXD, it will have no root if it is an XmlDocument

// in that case, simply use the document from the TXD

XmlDocument root = node.OwnerDocument;

if (null == root)

{

// if the XPath selects the TXD, it may

// so fix accordingly

root = txd.Document as XmlDocument;

if (null == root) return;

}

// create a new node and add it in

XmlElement newNode = root.CreateElement(nodeName, nodeNamespace);

node.AppendChild(newNode);

}

/// <summary>

/// Add an new node with a specified name into the node selected by the XPath

/// </summary>

/// <param name="txd">RuleEngine wrapper for an XmlDocument (or some part of it)</param>

/// <param name="xPath">XPath that must select a node (null or "" to use current node)</param>

/// <param name="nodeName">Name for the new node</param>

public void AddNode(TypedXmlDocument txd, string xPath, string nodeName)

{

// can we find the XPath indicated?

XmlNode node = LocateXPath(txd, xPath);

if (null == node) return;

// determine the root node for the document

// if the XPath selects the TXD, it will have no root if it is an XmlDocument

// in that case, simply use the document from the TXD

XmlDocument root = node.OwnerDocument;

if (null == root)

{

// if the XPath selects the TXD, it may

// so fix accordingly

root = txd.Document as XmlDocument;

if (null == root) return;

}

// create a new node and add it in

XmlElement newNode = root.CreateElement(nodeName);

node.AppendChild(newNode);

}

/// <summary>

/// Add an new node with a specified name and namespace into the node selected by the XPath

/// provided that it doesn't already exist

/// </summary>

/// <param name="txd">RuleEngine wrapper for an XmlDocument (or some part of it)</param>

/// <param name="xPath">XPath that must select a node (null or "" to use current node)</param>

/// <param name="nodeName">Name for the new node</param>

/// <param name="nodeNamespace">Namespace for the new node</param>

public void AddNodeIfNotThere(TypedXmlDocument txd, string xPath, string nodeName, string nodeNamespace)

{

// can we find the XPath indicated?

XmlNode node = LocateXPath(txd, xPath);

if (null == node) return;

// does the new element already exist?

foreach (XmlNode child in node.ChildNodes)

{

if ((child.LocalName == nodeName) && (child.NamespaceURI == nodeNamespace)) return;

}

// determine the root node for the document

// if the XPath selects the TXD, it will have no root if it is an XmlDocument

// in that case, simply use the document from the TXD

XmlDocument root = node.OwnerDocument;

if (null == root)

{

// if the XPath selects the TXD, it may

// so fix accordingly

root = txd.Document as XmlDocument;

if (null == root) return;

}

// create a new node and add it in

XmlElement newNode = root.CreateElement(nodeName, nodeNamespace);

node.AppendChild(newNode);

}

/// <summary>

/// Add an new node with a specified name into the node selected by the XPath

/// provided that it doesn't already exist

/// </summary>

/// <param name="txd">RuleEngine wrapper for an XmlDocument (or some part of it)</param>

/// <param name="xPath">XPath that must select a node (null or "" to use current node)</param>

/// <param name="nodeName">Name for the new node</param>

public void AddNodeIfNotThere(TypedXmlDocument txd, string xPath, string nodeName)

{

// can we find the XPath indicated?

XmlNode node = LocateXPath(txd, xPath);

if (null == node) return;

// does the new element already exist?

foreach (XmlNode child in node.ChildNodes)

{

if (child.LocalName == nodeName) return;

}

// determine the root node for the document

// if the XPath selects the TXD, it will have no root if it is an XmlDocument

// in that case, simply use the document from the TXD

XmlDocument root = node.OwnerDocument;

if (null == root)

{

// if the XPath selects the TXD, it may

// so fix accordingly

root = txd.Document as XmlDocument;

if (null == root) return;

}

// create a new node and add it in

XmlElement newNode = root.CreateElement(nodeName);

node.AppendChild(newNode);

}

/// <summary>

/// Select the first node that the specified XPath points to inside the XmlDocument

/// </summary>

/// <param name="txd">RuleEngine wrapper for an XmlDocument (or some part of it)</param>

/// <param name="xPath">XPath that must select a node (null or "" to use current node)</param>

/// <returns></returns>

internal XmlNode LocateXPath(TypedXmlDocument txd, string xPath)

{

// does the TXD contain a node?

XmlNode parent = txd.Document;

if (null == parent) return null;

// is there an XPath specified? if not, return the parent

if ((xPath == null) || (xPath == string.Empty)) return parent;

// return the first node that the XPath points to

return parent.SelectSingleNode(xPath, txd.NamespaceManager);

}

}

}