/// <summary>
        /// Check for and convert inline XML dynamic value notation into <see cref="IDynamicValue"/> definitions.
        /// </summary>
        /// <param name="typeTable">The type table.</param>
        /// <param name="inputNode">The node to process.</param>
        /// <param name="exclusions">Any elements to exclude.</param>
        /// <returns></returns>
        public static XmlNode ConvertXmlToDynamicValues(NetReflectorTypeTable typeTable, XmlNode inputNode, params string[] exclusions)
        {
            var resultNode = inputNode;
            var doc = inputNode.OwnerDocument;
            var parameters = new List<XmlElement>();

            // Initialise the values from the reflection
            var inputMembers = new Dictionary<string, XmlMemberSerialiser>();
            buildMembers(ref inputMembers, typeTable, inputNode);

            var nodes = inputNode.SelectNodes("descendant::text()|descendant-or-self::*[@*]/@*");
            foreach (XmlNode nodeWithParam in nodes)
            {
                var text = nodeWithParam.Value;
                var isExcluded = CheckForExclusion(nodeWithParam, exclusions);
                if (!isExcluded && parameterRegex.Match(text).Success)
                {
                    // Generate the format string
                    var parametersEl = doc.CreateElement("parameters");
                    var index = 0;
                    var lastReplacement = string.Empty;
                    var format = parameterRegex.Replace(text, (match) =>
                    {
                        // Split into it's component parts
                        var parts = paramPartRegex.Split(match.Value.Substring(2, match.Value.Length - 3));

                        // Generate the value element
                        var dynamicValueEl = doc.CreateElement("namedValue");
                        dynamicValueEl.SetAttribute("name", parts[0].Replace("\\|", "|"));
                        if (parts.Length > 1)
                        {
                            dynamicValueEl.SetAttribute("value", parts[1].Replace("\\|", "|"));
                        }

                        parametersEl.AppendChild(dynamicValueEl);

                        // Generate the replacement
                        lastReplacement = string.Format(CultureInfo.CurrentCulture, "{{{0}{1}}}",
                            index++,
                            parts.Length > 2 ? ":" + parts[2].Replace("\\|", "|") : string.Empty);
                        return lastReplacement;
                    });

                    // Generate the dynamic value element
                    var replacementValue = string.Empty;
                    XmlElement replacementEl;
                    if (lastReplacement != format)
                    {
                        replacementEl = doc.CreateElement("replacementValue");
                        AddElement(replacementEl, "format", format);
                        replacementEl.AppendChild(parametersEl);
                    }
                    else
                    {
                        replacementEl = doc.CreateElement("directValue");
                        AddElement(replacementEl, "parameter", parametersEl.SelectSingleNode("namedValue/@name").InnerText);
                        var innerValue = parametersEl.SelectSingleNode("namedValue/@value");
                        if (innerValue != null)
                        {
                            replacementValue = innerValue.InnerText;
                            AddElement(replacementEl, "default", replacementValue);
                        }
                    }
                    parameters.Add(replacementEl);

                    // Generate the path
                    var propertyName = new StringBuilder();
                    var currentNode = nodeWithParam is XmlAttribute ? nodeWithParam : nodeWithParam.ParentNode;
                    var previousNode = currentNode;
                    var lastName = string.Empty;
                    bool hasDynamicValues = false;
                    while ((currentNode != null) && (currentNode.NodeType != XmlNodeType.Document))
                    {
                        var nodeName = currentNode.Name;

                        var currentNodeType = typeTable.ContainsType(nodeName) ? typeTable[nodeName] : null;
                        if (currentNodeType != null)
                        {
                            hasDynamicValues = currentNodeType.Type.
                                GetInterface(typeof(IWithDynamicValuesItem).Name) != null;
                            if (hasDynamicValues)
                                break;
                        }
                        
                        // we don't want to take into account the input node, but we need to know if it has
                        // dynamic values, hence the break here and not in the while loop
                        if (currentNode == inputNode)
                            break;

                        // Check if we are dealing with an array
                        if (inputMembers.ContainsKey(nodeName) && inputMembers[nodeName].ReflectorMember.MemberType.IsArray)
                        {
                            // Do some convoluted processing to handle array items
                            propertyName.Remove(0, lastName.Length + 1); // Remove the previous name, since this is now an index position
                            var position = 0;
                            var indexNode = previousNode;

                            // Find the index of the node
                            while (indexNode.PreviousSibling != null)
                            {
                                if (indexNode.NodeType != XmlNodeType.Comment)
                                    position++;
                                indexNode = indexNode.PreviousSibling;
                            }

                            // Add the node as an indexed node
                            propertyName.Insert(0, "." + nodeName + "[" + position.ToString(CultureInfo.CurrentCulture) + "]");
                        }
                        else
                        {
                            // Just add the node name
                            propertyName.Insert(0, "." + nodeName);
                        }

                        // Move to the parent
                        lastName = nodeName;
                        previousNode = currentNode;
                        currentNode = getParentNode(currentNode);
                    }
                    propertyName.Remove(0, 1);
                    AddElement(replacementEl, "property", propertyName.ToString());

                    // Set a replacement value
                    nodeWithParam.Value = replacementValue;

                    // add the parameters already there if the current node has dynamic values
                    if (hasDynamicValues)
                        addParameters(ref parameters, currentNode);
                }
            }

            // Add the remaining parameters to the root element
            addParameters(ref parameters, inputNode);

            return resultNode;
        }
        private static void buildImputMembers(ref Dictionary<string, XmlMemberSerialiser> inputMembers, NetReflectorTypeTable typeTable, XmlNode inputNode)
        {
            var inputNodeType = typeTable.ContainsType(inputNode.Name) ? typeTable[inputNode.Name] : null;
            if (inputNodeType != null)
            {
                foreach (XmlMemberSerialiser value in inputNodeType.MemberSerialisers)
                {
                    if (value != null)
                    {
                        if (!inputMembers.ContainsKey(value.Attribute.Name))
                            inputMembers.Add(value.Attribute.Name, value);
                    }
                }
            }

            foreach (XmlNode childNode in inputNode.ChildNodes)
            {
                buildImputMembers(ref inputMembers, typeTable, childNode);
            }
        }
        private static void buildMembers(ref Dictionary<string, XmlMemberSerialiser> members, NetReflectorTypeTable typeTable, XmlNode node)
        {
            if (node == null)
                return;

            var nodeType = typeTable.ContainsType(node.Name) ? typeTable[node.Name] : null;
            if (nodeType != null)
            {
                foreach (XmlMemberSerialiser value in nodeType.MemberSerialisers)
                {
                    if (value != null)
                    {
                        if (!members.ContainsKey(value.Attribute.Name))
                            members.Add(value.Attribute.Name, value);
                    }
                }
            }

            foreach (XmlNode childNode in node.ChildNodes)
            {
                buildMembers(ref members, typeTable, childNode);
            }
        }
        /// <summary>
        /// Check for and convert inline XML dynamic value notation into <see cref="IDynamicValue"/> definitions.
        /// </summary>
        /// <param name="typeTable">The type table.</param>
        /// <param name="inputNode">The node to process.</param>
        /// <param name="exclusions">Any elements to exclude.</param>
        /// <returns></returns>
        public static XmlNode ConvertXmlToDynamicValues(NetReflectorTypeTable typeTable, XmlNode inputNode, params string[] exclusions)
        {
            var resultNode = inputNode;
            var doc = inputNode.OwnerDocument;
            var parameters = new List<XmlElement>();

            // Initialise the values from the reflection
            var inputNodeType = typeTable.ContainsType(inputNode.Name) ? typeTable[inputNode.Name] : null;
            var inputMembers = new Dictionary<string, XmlMemberSerialiser>();
            if (inputNodeType != null)
            {
                foreach (XmlMemberSerialiser value in inputNodeType.MemberSerialisers)
                {
                    if (value != null)
                    {
                        inputMembers.Add(value.Attribute.Name, value);
                    }
                }
            }

            var nodes = inputNode.SelectNodes("descendant::text()|descendant-or-self::*[@*]/@*");
            foreach (XmlNode nodeWithParam in nodes)
            {
                var text = nodeWithParam.Value;
                var isExcluded = CheckForExclusion(nodeWithParam, exclusions);
                if (!isExcluded && parameterRegex.Match(text).Success)
                {
                    // Generate the format string
                    var parametersEl = doc.CreateElement("parameters");
                    var index = 0;
                    var lastReplacement = string.Empty;
                    var format = parameterRegex.Replace(text, (match) =>
                    {
                        // Split into it's component parts
                        var parts = paramPartRegex.Split(match.Value.Substring(2, match.Value.Length - 3));

                        // Generate the value element
                        var dynamicValueEl = doc.CreateElement("namedValue");
                        dynamicValueEl.SetAttribute("name", parts[0].Replace("\\|", "|"));
                        if (parts.Length > 1)
                        {
                            dynamicValueEl.SetAttribute("value", parts[1].Replace("\\|", "|"));
                        }

                        parametersEl.AppendChild(dynamicValueEl);

                        // Generate the replacement
                        lastReplacement = string.Format("{{{0}{1}}}",
                            index++,
                            parts.Length > 2 ? ":" + parts[2].Replace("\\|", "|") : string.Empty);
                        return lastReplacement;
                    });

                    // Generate the dynamic value element
                    var replacementValue = string.Empty;
                    XmlElement replacementEl;
                    if (lastReplacement != format)
                    {
                        replacementEl = doc.CreateElement("replacementValue");
                        AddElement(replacementEl, "format", format);
                        replacementEl.AppendChild(parametersEl);
                    }
                    else
                    {
                        replacementEl = doc.CreateElement("directValue");
                        AddElement(replacementEl, "parameter", parametersEl.SelectSingleNode("namedValue/@name").InnerText);
                        var innerValue = parametersEl.SelectSingleNode("namedValue/@value");
                        if (innerValue != null)
                        {
                            replacementValue = innerValue.InnerText;
                            AddElement(replacementEl, "default", replacementValue);
                        }
                    }
                    parameters.Add(replacementEl);

                    // Generate the path
                    var propertyName = new StringBuilder();
                    var currentNode = nodeWithParam is XmlAttribute ? nodeWithParam : nodeWithParam.ParentNode;
                    var previousNode = currentNode;
                    var lastName = string.Empty;
                    while ((currentNode != inputNode) && (currentNode != null))
                    {
                        // Check if we are dealing with an array
                        var nodeName = currentNode.Name;
                        if (inputMembers.ContainsKey(nodeName) && inputMembers[nodeName].ReflectorMember.MemberType.IsArray)
                        {
                            // Do some convoluted processing to handle array items
                            propertyName.Remove(0, lastName.Length + 1);    // Remove the previous name, since this is now an index position
                            var position = 0;
                            var indexNode = previousNode;

                            // Find the index of the node
                            while (indexNode.PreviousSibling != null)
                            {
                                position++;
                                indexNode = indexNode.PreviousSibling;
                            }

                            // Add the node as an indexed node
                            propertyName.Insert(0, "." + nodeName + "[" + position.ToString() + "]");
                        }
                        else
                        {
                            // Just add the node name
                            propertyName.Insert(0, "." + nodeName);
                        }

                        // Move to the parent
                        lastName = nodeName;
                        previousNode = currentNode;
                        if (currentNode is XmlAttribute)
                        {
                            currentNode = (currentNode as XmlAttribute).OwnerElement;
                        }
                        else
                        {
                            currentNode = currentNode.ParentNode;
                        }
                    }
                    propertyName.Remove(0, 1);
                    AddElement(replacementEl, "property", propertyName.ToString());

                    // Set a replacement value
                    nodeWithParam.Value = replacementValue;
                }
            }

            // Add the parameters to the element
            if (parameters.Count > 0)
            {
                var parametersEl = inputNode.SelectSingleNode("dynamicValues");
                if (parametersEl == null)
                {
                    parametersEl = doc.CreateElement("dynamicValues");
                    inputNode.AppendChild(parametersEl);
                }

                foreach (var element in parameters)
                {
                    parametersEl.AppendChild(element);
                }
            }

            return resultNode;
        }