diff --git a/modules/doc/library/Doc/TocRenderer.php b/modules/doc/library/Doc/TocRenderer.php
new file mode 100644
index 000000000..8264c2d8e
--- /dev/null
+++ b/modules/doc/library/Doc/TocRenderer.php
@@ -0,0 +1,109 @@
+url = $url;
+ $this->urlParams = array_map(array($this, 'encodeUrlParam'), $urlParams);
+ }
+
+ public function beginIteration()
+ {
+ $this->content[] = '';
+ }
+
+ public function beginChildren()
+ {
+ $this->content[] = '
';
+ }
+
+ public function endChildren()
+ {
+ $this->content[] = '
';
+ }
+
+ /**
+ * Render the toc
+ *
+ * @param View $view
+ * @param Zend_View_Helper_Url $zendUrlHelper
+ *
+ * @return string
+ */
+ public function render(View $view, Zend_View_Helper_Url $zendUrlHelper)
+ {
+ foreach ($this as $node) {
+ $section = $node->getValue();
+ /* @var $section \Icinga\Module\Doc\Section */
+ $path = $zendUrlHelper->url(
+ array_merge(
+ $this->urlParams,
+ array(
+ 'chapterName' => $this->encodeUrlParam($section->getChapterTitle())
+ )
+ ),
+ $this->url,
+ false,
+ false
+ );
+ $url = $view->url($path);
+ $url->setAnchor($this->encodeAnchor($section->getId()));
+ $this->content[] = sprintf(
+ '%s',
+ $section->isNofollow() ? 'rel="nofollow" ' : '',
+ $url->getAbsoluteUrl(),
+ $view->escape($section->getTitle())
+ );
+ if (! $this->getInnerIterator()->current()->hasChildren()) {
+ $this->content[] = '';
+ }
+ }
+ return implode("\n", $this->content);
+ }
+}