For our own website, we decided to present a simple sitemap interface which enumerates all of our website's pages in a hierarchy based on its path and parent's path. We wanted the UI to generate the interface dynamically based on the contents of our sitemap.xml file so that we would not need to maintain our sitemap in more than one place. The challenge to this task is to take the data from the flat list of urls in the sitemap and display it as a hierarchy of paths and pages to the user. In order to accomplish this, we would need to be able to do the following:
- Convert the flat sitemap array into a recursive structure based on path sections.
- The sitemap starts out as a flat list. Each url value will be that page's full url.
- We want to represent this as an object where each path has children in the object, and they have their own children, etc.
- Determine which paths correspond to actual website pages and which don't.
- Some paths, such as /store/item are intermediate; they are not pages on their own but other site pages contain this in their paths.
- Recursively enumerate the paths.
- We want to show the paths to the user in a hierarchical manner so it is easy to distinguish children from parents.
In our system, we assemble the sitemap contents, then convert to JSON or XML, so we will not cover the process of converting from XML to JSON in this page, but there are external libraries which can take care of this conversion if needed.
Creating the Recursive Structure
In order to map our flat array to a recursive object, we will need to iterate over each path in the array and add new nested properties to the object as we go (if they don't already exist).
The code block above:
- Initializes our recursive object to an empty object called pathSplits.
- Iterates over the sitemap array, and for each entry:
- Removes the common siteBasePath from the url and splits it by "/".
- For each path string in the splitUrl array, and for each index:
- It creates a path entry in the pathSlits object if it doesn't exist.
- Sets the object reference to that path.
Once this code executes, pathSplits will look something like the code below. The path to an object can be followed via nested keys. If an object has a "" property, then that path corresponds to an actual page on the website. If not, then it corresponds to a partial path only, such as "/store/item", which is not a page on its own.
Map the Recursive Structure to A Consumable Object
The object we've just created contains the structure for our hierarchy. Now we will traverse the structure and map the properties into something which will be easy to use to render the UI.
Display the Results on the Document
Since our website is developed with Angular, we have implemented the sitemap page using two Angular components:
- Page Component: the component which defines the content of the entire page.
- Recursive Sitemap Component: component which accepts a recursive sitemap object, displays its page, then recursively calls itself to display its children.
The page component uses one sitemap component for each of the initial page children, then the sitemap component handles the rest internally. The recursion will eventually end when it reaches paths which have no children.
The HTML above is nothing fancy; it shows an arrow with the current page name, then shows its children. Each level is indented by an additional margin to the left.
Creating the Recursive Angular Component
The approach taken in the HTML template above uses the concept of recursive Angular components to recursively enumerate the items within the sitemap. For a more detailed explanation of this concept, please visit our dev page below:
Putting it All Together
All of the relevant code is shown in the code boxes below. Using this strategy, we were able to implement the sitemap for this website, which can be viewed on our sitemap page.