Inheritance: SitemapItem
        private static void AddDescendants(TaxonomyNode taxonomyNode, NavigationFilter filter, Localization localization)
        {
            using (new Tracer(taxonomyNode, filter, localization))
            {
                // First recurse (depth-first)
                IList<SitemapItem> children = taxonomyNode.Items;
                foreach (TaxonomyNode childNode in children.OfType<TaxonomyNode>())
                {
                    AddDescendants(childNode, filter, localization);
                }

                // Add descendants (on the way back)
                string taxonomyId;
                string keywordId;
                string pageId;
                ParseSitemapItemId(taxonomyNode.Id, out taxonomyId, out keywordId, out pageId);
                string publicationId = localization.LocalizationId;
                string taxonomyUri = string.Format("tcm:{0}-{1}-512", publicationId, taxonomyId);
                string keywordUri = string.IsNullOrEmpty(keywordId) ? taxonomyUri : string.Format("tcm:{0}-{1}-1024", publicationId, keywordId);

                IEnumerable<SitemapItem> additionalChildren = ExpandDescendants(keywordUri, taxonomyUri, filter, localization);
                foreach (SitemapItem additionalChildItem in additionalChildren.Where(childItem => children.All(i => i.Id != childItem.Id)))
                {
                    children.Add(additionalChildItem);
                }

                // Ensure that children are ordered correctly
                taxonomyNode.Items = children.OrderBy(i => i.OriginalTitle).ToList();
            }
        }
        private static TaxonomyNode CreateTaxonomyNode(Keyword keyword, int expandLevels, NavigationFilter filter, Localization localization)
        {
            string taxonomyId = keyword.TaxonomyUri.Split('-')[1];
            bool isRoot = (keyword.KeywordUri == keyword.TaxonomyUri);
            int classifiedItemsCount = keyword.ReferencedContentCount;
            string taxonomyNodeUrl = null;

            List<SitemapItem> childItems = new List<SitemapItem>();
            if (expandLevels != 0)
            {
                // Add child SitemapItems for child Taxonomy Nodes (ordered by title, including sequence prefix if any)
                IEnumerable<TaxonomyNode> childTaxonomyNodes = keyword.KeywordChildren.Cast<Keyword>()
                    .Select(kw => CreateTaxonomyNode(kw, expandLevels - 1, filter, localization));
                childItems.AddRange(childTaxonomyNodes);

                if (classifiedItemsCount > 0 && filter.DescendantLevels != 0)
                {
                    // Add child SitemapItems for classified Pages (ordered by title)
                    SitemapItem[] pageSitemapItems = ExpandClassifiedPages(keyword, taxonomyId, localization);
                    childItems.AddRange(pageSitemapItems);

                    // If the Taxonomy Node contains an Index Page (i.e. URL path ending with "/index"), we put the Page's SG URL on the Taxonomy Node.
                    string indexPageUrlPath = pageSitemapItems.Select(i => i.Url).FirstOrDefault(url => url.EndsWith(Constants.IndexPageUrlSuffix, StringComparison.InvariantCultureIgnoreCase));
                    if (indexPageUrlPath != null)
                    {
                        // Strip off "/index" URL suffix so we get the Page's SG URL (except for the Site Home Page, where we use "/")
                        taxonomyNodeUrl = (indexPageUrlPath.Equals(Constants.IndexPageUrlSuffix, StringComparison.InvariantCultureIgnoreCase)) ? "/" :
                            indexPageUrlPath.Substring(0, indexPageUrlPath.Length - Constants.IndexPageUrlSuffix.Length);
                    }
                }

                childItems = childItems.OrderBy(i => i.OriginalTitle).ToList();
            }

            string sequencePrefix;
            TaxonomyNode result = new TaxonomyNode
            {
                Id = isRoot ? string.Format("t{0}", taxonomyId) : FormatKeywordNodeId(keyword.KeywordUri, taxonomyId),
                Type =  SitemapItem.Types.TaxonomyNode,
                OriginalTitle = keyword.KeywordName,
                Title = StripSequencePrefix(keyword.KeywordName, out sequencePrefix),
                Url = taxonomyNodeUrl,
                Visible = !string.IsNullOrEmpty(sequencePrefix) && !string.IsNullOrEmpty(taxonomyNodeUrl),
                Items = childItems,
                Key = keyword.KeywordKey,
                Description = keyword.KeywordDescription,
                IsAbstract = keyword.IsAbstract,
                HasChildNodes = keyword.HasChildren || (classifiedItemsCount > 0),
                ClassifiedItemsCount = classifiedItemsCount
            };

            if (childItems != null)
            {
                foreach (SitemapItem childItem in childItems)
                {
                    childItem.Parent = result;
                }
            }

            return result;
        }
 private static void AssertExpectedTaxonomyNode(TaxonomyNode taxonomyNode, string expectedTitle, int expectedNumberOfChildItems, string subjectName)
 {
     Assert.IsNotNull(taxonomyNode, subjectName);
     Assert.AreEqual(expectedTitle, taxonomyNode.Title, subjectName + ".Title");
     Assert.IsNotNull(taxonomyNode.Items, subjectName + ".Items");
     Assert.AreEqual(expectedNumberOfChildItems, taxonomyNode.Items.Count, subjectName + ".Items.Count");
 }