/**
  * Render formatting options onto text
  */
 public function render()
 {
     $offset = 0;
     foreach ($this->formats as $format) {
         $attrs = $this->attributes($format->type, !empty($format->attrs) ? $format->attrs : null);
         $opening = '<' . $format->type . "{$attrs}>";
         $closing = '</' . $format->type . '>';
         $this->text = UTF8::substr_replace($this->text, $opening, $format->from + $offset, 0);
         $offset += strlen($opening);
         $this->text = UTF8::substr_replace($this->text, $closing, $format->to + $offset, 0);
         $offset += strlen($closing);
     }
     // create a temporary document and load the plain html
     $tmpDoc = new DOMDocument();
     // purify HTML to convert HTML chars in text nodes etc.
     $config = HTMLPurifier_Config::createDefault();
     $config->set('HTML.Trusted', true);
     $this->text = (new HTMLPurifier($config))->purify($this->text);
     $tmpDoc->loadHTML('<?xml encoding="UTF-8"><html><body>' . $this->text . '</body></html>');
     $tmpDoc->encoding = 'UTF-8';
     // import and attach the created nodes to the paragraph
     foreach ($tmpDoc->getElementsByTagName('body')->item(0)->childNodes as $node) {
         $node = $this->dom->importNode($node, true);
         $this->paragraph->appendChild($node);
     }
     return $this->paragraph;
 }