private static void BuildFolderPaths(SitemapBuildingData pagesData, IEnumerable<XElement> elements, IDictionary<string, Guid> urlToIdLookup, IPageUrlBuilder builder)
        {
            foreach (XElement element in elements)
            {
                Guid pageId = new Guid(element.Attribute(AttributeNames.Id).Value);

                IPage page = pagesData.PageById[pageId];
                IPageStructure pageStructure = pagesData.StructureById[pageId];
                if (pageStructure == null)
                {
                    continue;
                }

                Guid parentId = pageStructure.ParentId;

                PageUrlSet pageUrls = builder.BuildUrlSet(page, parentId);
                if(pageUrls == null)
                {
                    continue;
                }

                element.Add(new XAttribute(AttributeNames.URL, pageUrls.PublicUrl));

                string lookupUrl = pageUrls.PublicUrl;

                if(pageUrls.FriendlyUrl != null)
                {
                    element.Add(new XAttribute(AttributeNames.FriendlyUrl, pageUrls.FriendlyUrl));
                }

                //// FolderPath isn't used any more
                //element.Add(new XAttribute("FolderPath", builder.FolderPaths[pageId]));

                element.Add(new XAttribute(AttributeNames.Depth, 1 + element.Ancestors(PageElementName).Count()));

                // NOTE: urlToIdLookup is obsolete, but old API needs it
                if (urlToIdLookup.ContainsKey(lookupUrl))
                {
                    Log.LogError(LogTitle, "Multiple pages share the same path '{0}', page ID: '{1}'. Duplicates are ignored.".FormatWith(pageUrls.PublicUrl, pageId));
                    continue;
                }

                urlToIdLookup.Add(lookupUrl, pageId);

                BuildFolderPaths(pagesData, element.Elements(), urlToIdLookup, builder);
            }
        }
 private static void BuildFolderPaths(SitemapBuildingData pagesData, IEnumerable<XElement> roots, IPageUrlBuilder pageUrlBuilder, IDictionary<string, Guid> urlToIdLookup)
 {
     BuildFolderPaths(pagesData, roots, urlToIdLookup, pageUrlBuilder);
 }
        private static Map BuildMap(UrlSpace urlSpace)
        {
            using (DebugLoggingScope.MethodInfoScope)
            {
                var publicationScope = DataScopeManager.CurrentDataScope.ToPublicationScope();
                var localizationScope = LocalizationScopeManager.CurrentLocalizationScope;

                Log.LogVerbose(LogTitle, string.Format("Building page structure in the publication scope '{0}' with the localization scope '{1}'", publicationScope, localizationScope));

                var urlToIdLookup = new Dictionary<string, Guid>();
                var idToUrlLookup = new Dictionary<Guid, string>();

                var pagesData = new SitemapBuildingData();

                var pageToToChildElementsTable = new Hashtable<Guid, List<PageTreeInfo>>();
                foreach (IPage page in pagesData.Pages)
                {
                    IPageStructure pageStructure = pagesData.StructureById[page.Id];

                    if (pageStructure == null)
                    {
                        Log.LogWarning(LogTitle, "Failed to find PageStructure data. Page ID is '{0}'".FormatWith(page.Id));
                        continue;
                    }

                    int localOrdering = pageStructure.LocalOrdering;

                    var pageElement = new XElement(ElementNames.Page,
                         new XAttribute(AttributeNames.Id, page.Id),
                         new XAttribute(AttributeNames.Title, page.Title),
                         (string.IsNullOrEmpty(page.MenuTitle) ? null : new XAttribute(AttributeNames.MenuTitle, page.MenuTitle)),
                         new XAttribute(AttributeNames.UrlTitle, page.UrlTitle),
                         new XAttribute(AttributeNames.Description, page.Description ?? string.Empty),
                         new XAttribute(AttributeNames.ChangedDate, page.ChangeDate),
                         new XAttribute(AttributeNames.ChangedBy, page.ChangedBy ?? string.Empty));

                    var list = pageToToChildElementsTable[pageStructure.ParentId];

                    if (list == null)
                    {
                        list = new List<PageTreeInfo>();
                        pageToToChildElementsTable[pageStructure.ParentId] = list;
                    }

                    list.Add(new PageTreeInfo
                    {
                        ID = page.Id,
                        LocalOrdering = localOrdering,
                        Element = pageElement
                    });
                }

                var root = new XElement("root");

                BuildXmlStructure(root, Guid.Empty, pageToToChildElementsTable, 100);

#pragma warning disable 612
                var pageUrlBuilder = PageUrls.UrlProvider.CreateUrlBuilder(publicationScope, localizationScope, urlSpace);
                BuildFolderPaths(pagesData, root.Elements(), pageUrlBuilder, urlToIdLookup);
#pragma warning restore 612

                foreach (var urlLookupEntry in urlToIdLookup)
                {
                    idToUrlLookup.Add(urlLookupEntry.Value, urlLookupEntry.Key);
                }

                var lowerCaseUrlToIdLookup = new Dictionary<string, Guid>();

                foreach (KeyValuePair<string, Guid> keyValuePair in urlToIdLookup)
                {
                    string loweredUrl = keyValuePair.Key.ToLowerInvariant();

                    if (lowerCaseUrlToIdLookup.ContainsKey(loweredUrl))
                    {
                        if (!_knownNotUniqueUrls.Contains(loweredUrl))
                        {
                            lock (_knownNotUniqueUrls)
                            {
                                _knownNotUniqueUrls.Add(loweredUrl);
                            }
                            Log.LogError(LogTitle, "Multiple pages share the same path '{0}'. Page ID: '{1}'. Duplicates are ignored.".FormatWith(loweredUrl, keyValuePair.Value));
                        }
                        
                        continue;
                    }

                    lowerCaseUrlToIdLookup.Add(loweredUrl, keyValuePair.Value);
                }

                return new Map
                           {
                               IdToUrlLookup = idToUrlLookup,
                               UrlToIdLookup = urlToIdLookup,
                               LowerCaseUrlToIdLookup = lowerCaseUrlToIdLookup,
                               RootPagesLookup = root.Elements(),
                               PageUrlBuilder = pageUrlBuilder
                           };
            }
        }