/// <summary>
        /// Recursively processes our XML document, parsing our siteMapNodes and dynamicNode(s).
        /// </summary>
        /// <param name="parentNode">The parent node to process.</param>
        /// <param name="parentElement">The corresponding parent XML element.</param>
        /// <param name="processFlags">Flags to indicate which nodes to process.</param>
        /// <param name="helper">The node helper.</param>
        protected virtual IList <ISiteMapNodeToParentRelation> ProcessXmlNodes(ISiteMapNode parentNode, XElement parentElement, NodesToProcess processFlags, ISiteMapNodeHelper helper)
        {
            var  result = new List <ISiteMapNodeToParentRelation>();
            bool processStandardNodes = (processFlags & NodesToProcess.StandardNodes) == NodesToProcess.StandardNodes;
            bool processDynamicNodes  = (processFlags & NodesToProcess.DynamicNodes) == NodesToProcess.DynamicNodes;

            foreach (XElement node in parentElement.Elements())
            {
                if (node.Name != xmlNameProvider.NodeName)
                {
                    // If the current node is not one of the known node types throw and exception
                    throw new MvcSiteMapException(string.Format(Resources.Messages.XmlSiteMapNodeProviderInvalidSiteMapElement, helper.SiteMapCacheKey));
                }

                var child = GetSiteMapNodeFromXmlElement(node, parentNode, helper);

                if (processStandardNodes && !child.Node.HasDynamicNodeProvider)
                {
                    result.Add(child);

                    // Continue recursively processing the XML file.
                    result.AddRange(ProcessXmlNodes(child.Node, node, processFlags, helper));
                }
                else if (processDynamicNodes && child.Node.HasDynamicNodeProvider)
                {
                    // We pass in the parent node key as the default parent because the dynamic node (child) is never added to the sitemap.
                    var dynamicNodes = helper.CreateDynamicNodes(child, parentNode.Key);

                    foreach (var dynamicNode in dynamicNodes)
                    {
                        result.Add(dynamicNode);

                        if (!this.useNestedDynamicNodeRecursion)
                        {
                            // Recursively add non-dynamic children for every dynamic node
                            result.AddRange(ProcessXmlNodes(dynamicNode.Node, node, NodesToProcess.StandardNodes, helper));
                        }
                        else
                        {
                            // Recursively process both dynamic nodes and static nodes.
                            // This is to allow V3 recursion behavior for those who depended on it - it is not a feature.
                            result.AddRange(ProcessXmlNodes(dynamicNode.Node, node, NodesToProcess.All, helper));
                        }
                    }

                    if (!this.useNestedDynamicNodeRecursion)
                    {
                        // Process the next nested dynamic node provider. We pass in the parent node as the default
                        // parent because the dynamic node definition node (child) is never added to the sitemap.
                        result.AddRange(ProcessXmlNodes(parentNode, node, NodesToProcess.DynamicNodes, helper));
                    }
                    else
                    {
                        // Continue recursively processing the XML file.
                        // Can't figure out why this is here, but this is the way it worked in V3 and if
                        // anyone depends on the broken recursive behavior, they probably also depend on this.
                        result.AddRange(ProcessXmlNodes(child.Node, node, processFlags, helper));
                    }
                }
            }
            return(result);
        }
        /// <summary>
        /// Recursively processes our XML document, parsing our siteMapNodes and dynamicNode(s).
        /// </summary>
        /// <param name="parentNode">The parent node to process.</param>
        /// <param name="parentElement">The correspoding parent XML element.</param>
        /// <param name="processFlags">Flags to indicate which nodes to process.</param>
        /// <param name="helper">The node helper.</param>
        protected virtual IList<ISiteMapNodeToParentRelation> ProcessXmlNodes(ISiteMapNode parentNode, XElement parentElement, NodesToProcess processFlags, ISiteMapNodeHelper helper)
        {
            var result = new List<ISiteMapNodeToParentRelation>();
            bool processStandardNodes = (processFlags & NodesToProcess.StandardNodes) == NodesToProcess.StandardNodes;
            bool processDynamicNodes = (processFlags & NodesToProcess.DynamicNodes) == NodesToProcess.DynamicNodes;

            foreach (XElement node in parentElement.Elements())
            {
                if (node.Name != xmlNameProvider.NodeName)
                {
                    // If the current node is not one of the known node types throw and exception
                    throw new MvcSiteMapException(String.Format(Resources.Messages.XmlSiteMapNodeProviderInvalidSiteMapElement, helper.SiteMapCacheKey));
                }

                var child = GetSiteMapNodeFromXmlElement(node, parentNode, helper);

                if (processStandardNodes && !child.Node.HasDynamicNodeProvider)
                {
                    result.Add(child);

                    // Continue recursively processing the XML file.
                    result.AddRange(ProcessXmlNodes(child.Node, node, processFlags, helper));
                }
                else if (processDynamicNodes && child.Node.HasDynamicNodeProvider)
                {
                    // We pass in the parent node key as the default parent because the dynamic node (child) is never added to the sitemap.
                    var dynamicNodes = helper.CreateDynamicNodes(child, parentNode.Key);

                    foreach (var dynamicNode in dynamicNodes)
                    {
                        result.Add(dynamicNode);

                        if (!this.useNestedDynamicNodeRecursion)
                        {
                            // Recursively add non-dynamic childs for every dynamic node
                            result.AddRange(ProcessXmlNodes(dynamicNode.Node, node, NodesToProcess.StandardNodes, helper));
                        }
                        else
                        {
                            // Recursively process both dynamic nodes and static nodes.
                            // This is to allow V3 recursion behavior for those who depended on it - it is not a feature.
                            result.AddRange(ProcessXmlNodes(dynamicNode.Node, node, NodesToProcess.All, helper));
                        }
                    }

                    if (!this.useNestedDynamicNodeRecursion)
                    {
                        // Process the next nested dynamic node provider. We pass in the parent node as the default
                        // parent because the dynamic node definition node (child) is never added to the sitemap.
                        result.AddRange(ProcessXmlNodes(parentNode, node, NodesToProcess.DynamicNodes, helper));
                    }
                    else
                    {
                        // Continue recursively processing the XML file.
                        // Can't figure out why this is here, but this is the way it worked in V3 and if
                        // anyone depends on the broken recursive behavior, they probably also depend on this.
                        result.AddRange(ProcessXmlNodes(child.Node, node, processFlags, helper));
                    }
                }
            }
            return result;
        }