/**
  * Render the presentation and return the result.
  *
  * @param      AgaviTemplateLayer The template layer to render.
  * @param      array              The template variables.
  * @param      array              The slots.
  * @param      array              Associative array of additional assigns.
  *
  * @return     string A rendered result.
  *
  * @author     David Zülke <*****@*****.**>
  * @since      1.1.0
  */
 public function render(AgaviTemplateLayer $layer, array &$attributes = array(), array &$slots = array(), array &$moreAssigns = array())
 {
     if ($this->getParameter('envelope', true)) {
         if (!$moreAssigns['inner'] instanceof DOMDocument) {
             // plain text, load it as a document
             try {
                 $inner = $this->loadDomDocumentXml($moreAssigns['inner']);
             } catch (DOMException $e) {
                 throw new AgaviRenderException(sprintf("Unable to load input document for layer '%s'.\n\n%s", $layer->getName(), $e->getMessage()));
             }
         } else {
             $inner = $moreAssigns['inner'];
         }
         // construct envelope
         $doc = new DOMDocument();
         $doc->appendChild($doc->createElementNS(self::ENVELOPE_XMLNS, 'envelope'));
         // inner content container
         $doc->documentElement->appendChild($innerWrapper = $doc->createElementNS(self::ENVELOPE_XMLNS, 'inner'));
         $innerWrapper->appendChild($doc->importNode($inner->documentElement, true));
         // slots container
         $slotsWrapper = $doc->createElementNS(self::ENVELOPE_XMLNS, 'slots');
         $doc->documentElement->appendChild($slotsWrapper);
         // flatten slots, iterate and wrap them each
         $flattenedSlots = AgaviArrayPathDefinition::flatten($slots);
         foreach ($flattenedSlots as $slotName => $slotContent) {
             if (!$slotContent instanceof DOMDocument) {
                 try {
                     $slot = $this->loadDomDocumentXml($slotContent);
                 } catch (Exception $e) {
                     throw new AgaviRenderException(sprintf("Unable to load contents for slot '%s'.\n\n%s", $slotName, $e->getMessage()));
                 }
             } else {
                 $slot = $slotContent;
             }
             $slotWrapper = $doc->createElementNS(self::ENVELOPE_XMLNS, 'slot');
             $slotWrapper->setAttribute('name', $slotName);
             $slotWrapper->appendChild($doc->importNode($slot->documentElement, true));
             $slotsWrapper->appendChild($slotWrapper);
         }
     } else {
         if (!$moreAssigns['inner'] instanceof DOMDocument) {
             // plain text, load it as a document
             $doc = $this->loadDomDocumentXml($moreAssigns['inner']);
         } else {
             $doc = $moreAssigns['inner'];
         }
         // This will pretty much never work, so we're not doing it. Users must enable the envelope feature to use slots.
         // Warning: XSLTProcessor::transformToXml() [xsltprocessor.transformtoxml]: Cannot create XPath expression (string contains both quote and double-quotes)
         // $flattenedSlots = AgaviArrayPathDefinition::flatten($slots);
         // foreach($flattenedSlots as $slotName => $slotContent) {
         // 	if($slotContent instanceof DOMDocument) {
         // 		$slotContent = $slotContent->saveXML();
         // 	}
         // 	$xsl->setParameter('', 'slot:' . $slotName, addslashes($slotContent));
         // }
     }
     try {
         $xslt = $this->loadDomDocument($layer->getResourceStreamIdentifier());
     } catch (DOMException $e) {
         throw new AgaviRenderException(sprintf("Unable to load template '%s'.\n\n%s", $layer->getResourceStreamIdentifier(), $e->getMessage()));
     }
     $xsl = new XSLTProcessor();
     $xsl->importStylesheet($xslt);
     foreach ($attributes as $name => $attribute) {
         if (is_scalar($attribute) || is_object($attribute) && method_exists($attribute, '__toString')) {
             $xsl->setParameter('', $name, $attribute);
         }
     }
     return $xsl->transformToXML($doc);
 }