diff --git a/src/Document.php b/src/Document.php
index 81b81a10972ec87cadf828fe8bec10817eb0e7d3..782ae868555b21d6e48ee555baf7e48fb25fea40 100644
--- a/src/Document.php
+++ b/src/Document.php
@@ -78,6 +78,12 @@ class Document
      */
     private $tmpDir;
 
+    /**
+     * @var array 
+     */
+    private $formatters = [];
+    
+
     /**
      * @var array
      */
@@ -350,6 +356,29 @@ class Document
 
 
 
+    /**
+     * @param string $variable
+     * @param mixed $value
+     *
+     * @return string
+     */
+    public function formatValue(string $variable, $value): string
+    {
+        if (isset($this->formatters[$variable]) && $format = $this->formatters[$variable]){
+            if (is_callable($format)){
+                $value = $format($value);
+            }
+        }
+
+        if (is_float($value)){
+            return number_format($value, 2, ',', ' ');
+        }
+
+        return (string)$value;
+    }
+
+
+
     /**
      * Retourne les espaces de nom associés à leurs URI respectives sous forme de tableau associatif
      *
@@ -717,6 +746,31 @@ class Document
 
 
 
+    /**
+     * @return array
+     */
+    public function getFormatters(): array
+    {
+        return $this->formatters;
+    }
+
+
+
+    /**
+     * @param string $variable
+     * @param mixed $format
+     *
+     * @return Document
+     */
+    public function addFormatter(string $variable, $format): Document
+    {
+        $this->formatters[$variable] = $format;
+        
+        return $this;
+    }
+
+
+
     /**
      * PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++.
      * The destructor method will be called as soon as all references to a particular object are removed or
diff --git a/src/Publisher.php b/src/Publisher.php
index 3a4b3cbfa381be2ab06e2e3de83155d7ce482631..22fd9506f93010fa311f5776e5c1dee30c03548f 100644
--- a/src/Publisher.php
+++ b/src/Publisher.php
@@ -13,6 +13,9 @@ class Publisher
 {
     const PAGE_BREAK_NAME = 'UNICAEN_PAGE_BREAK';
 
+    const PARAGRAPH = 'text:p';
+    const TABLE_ROW = 'table:table-row';
+
     /**
      * Lecteur de fichier OpenDocument
      *
@@ -51,6 +54,11 @@ class Publisher
      */
     private $outContent;
 
+    /**
+     * @var bool
+     */
+    private $published = false;
+
 
 
     /**
@@ -77,6 +85,16 @@ class Publisher
 
 
 
+    /**
+     * @return DOMElement
+     */
+    public function getBody(): DOMElement
+    {
+        return $this->body;
+    }
+
+
+
     /**
      * Peuple l'instance courante du document et l'ajoute à la suite du fichier
      *
@@ -161,10 +179,6 @@ class Publisher
 
 
 
-
-
-
-
     public function getSections(DOMElement $element): array
     {
         $textNs = $this->getDocument()->getNamespaceUrl('text');
@@ -194,23 +208,26 @@ class Publisher
 
     /**
      * @param DOMElement $element
-     * @param string     $value
+     * @param mixed      $value
      *
      * @return Publisher
      */
-    public function setVariable(DOMElement $element, string $value): Publisher
+    protected function setVariable(DOMElement $element, $value): Publisher
     {
         $textNs = $this->getDocument()->getNamespaceUrl('text');
-
         $document = $element->ownerDocument;
 
-        $value = explode("\n", $value);
+        if (is_string($value) && false !== strpos($value, "\n")){
+            $value = explode("\n", $value);
+        }else{
+            $value = (array)$value;
+        }
         for ($i = 0; $i < count($value); $i++) {
             if ($i > 0) {
                 $returnVNode = $document->createElementNS($textNs, 'text:line-break');
                 $element->parentNode->insertBefore($returnVNode, $element);
             }
-            $vText = $document->createTextNode($value[$i]);
+            $vText = $document->createTextNode($this->getDocument()->formatValue($element->nodeValue,$value[$i]));
             $element->parentNode->insertBefore($vText, $element);
         }
         $element->parentNode->removeChild($element);
@@ -264,8 +281,16 @@ class Publisher
      * @return Publisher
      * @throws Exception
      */
-    private function publishBegin(): Publisher
+    public function publishBegin(): Publisher
     {
+        /* On récupère le content du document */
+        $this->content = new DOMDocument();
+        $this->content->loadXML($this->getDocument()->getContent()->saveXML());
+
+        if ($this->isAutoBreak()) {
+            $this->addPageBreakStyle();
+        }
+
         $contentText              = $this->content->saveXML();
         $officeDocumentContentPos = strpos($contentText, '<office:document-content');
         $length                   = strpos($contentText, '>', $officeDocumentContentPos) + 1;
@@ -291,6 +316,8 @@ class Publisher
             }
         }
 
+        $this->body = $this->content->getElementsByTagNameNS($this->getDocument()->getNamespaceUrl('office'), 'text')[0];
+
         return $this;
     }
 
@@ -299,10 +326,14 @@ class Publisher
     /**
      * @return Publisher
      */
-    private function publishEnd(): Publisher
+    public function publishEnd(): Publisher
     {
         $this->out("</office:body></office:document-content>");
 
+        /* On renvoie le content dans le document */
+        $this->getDocument()->getArchive()->addFromString('content.xml', $this->outContent);
+        $this->published = true;
+
         return $this;
     }
 
@@ -315,8 +346,12 @@ class Publisher
      * @return Publisher
      * @throws Exception
      */
-    private function publishValues(DOMElement $element, array $values): Publisher
+    public function publishValues(DOMElement $element, array $values): Publisher
     {
+        if ($element === $this->body) {
+            $this->getDocument()->getStylist()->setVariables($values);
+        }
+
         $variables = $this->getVariables($element);
         $sections  = $this->getSections($element);
 
@@ -362,6 +397,10 @@ class Publisher
             }
         }
 
+        if ($element === $this->body) {
+            $this->out($this->content->saveXML($element));
+        }
+
         return $this;
     }
 
@@ -370,14 +409,67 @@ class Publisher
     /**
      * @param DOMElement $element
      * @param string     $parent
-     * @param array      $values
+     * @param string     $variable
+     *
+     * @return DOMElement
+     * @throws Exception
+     */
+    public function getSubDoc(DOMElement $element, string $parent, string $variable): DOMElement
+    {
+        $variables = $this->getVariables($element);
+        if (!isset($variables[$variable][0])) {
+            throw new \Exception('La variable "' . $variable . '"" n\'a pas été trouvée dans le document');
+        }
+
+        return $this->getSubDocWithVariable($variables[$variable][0], $parent);
+    }
+
+
+
+    /**
+     * @param DOMElement $element
      *
      * @return Publisher
      */
-    private function publishSubData(DOMElement $element, string $parent, array $values): Publisher
+    public function remove(DOMElement $element): Publisher
+    {
+        $element->parentNode->removeChild($element);
+
+        return $this;
+    }
+
+
+
+    /**
+     * @param DOMElement $subDoc
+     * @param array      $variables
+     * @param DOMElement $refNode
+     *
+     * @return Publisher
+     */
+    public function publishBefore(DOMElement $subDoc, array $variables, DOMElement $refNode): Publisher
+    {
+        $node = $subDoc->cloneNode(true);
+        $this->publishValues($node, $variables);
+        $refNode->parentNode->insertBefore($node, $refNode);
+
+        return $this;
+    }
+
+
+
+    /**
+     * @param DOMElement $element
+     * @param string     $parent
+     * @param DOMElement $variable
+     *
+     * @return DOMElement
+     * @throws Exception
+     */
+    private function getSubDocWithVariable(DOMElement $element, string $parent): DOMElement
     {
         if ($element->tagName == 'text:section') {
-            $parentNode = $element; // C'est la section qui est dupliquée
+            return $element; // C'est la section qui est dupliquée
         } else {
             $i     = 10;
             $found = false;
@@ -392,18 +484,31 @@ class Publisher
             if (!$found) {
                 throw new \Exception('Le noeud parent de type ' . $parent . ' n\'a pas été trouvé');
             }
+
+            return $parentNode;
         }
+    }
+
+
+
+    /**
+     * @param DOMElement $element
+     * @param string     $parent
+     * @param array      $values
+     *
+     * @return Publisher
+     */
+    private function publishSubData(DOMElement $element, string $parent, array $values): Publisher
+    {
+        $parentNode = $this->getSubDocWithVariable($element, $parent);
 
         foreach ($values as $vals) {
             $clone = $parentNode->cloneNode(true);
             $this->publishValues($clone, $vals);
-
-            $parentNode->parentNode->insertBefore($clone, $parentNode);
+            $this->insertBefore($clone, $parentNode);
         }
 
-        $parentNode->parentNode->removeChild($parentNode);
-
-        return $this;
+        return $this->remove($parentNode);
     }
 
 
@@ -413,24 +518,14 @@ class Publisher
      */
     public function publish()
     {
-        /* On récupère le content du document */
-        $this->content = new DOMDocument();
-        $this->content->loadXML($this->getDocument()->getContent()->saveXML());
-
-        if ($this->isAutoBreak()) {
-            $this->addPageBreakStyle();
-        }
-
         $this->publishBegin();
-        $this->body = $this->content->getElementsByTagNameNS($this->getDocument()->getNamespaceUrl('office'), 'text')[0];
 
         $first = true;
         foreach ($this->values as $values) {
             $bodyNode = $this->body->cloneNode(true);
-            if ($first){
-                $this->getDocument()->getStylist()->setVariables($values);
+            if ($first) {
                 $first = false;
-            }elseif($this->isAutoBreak()){
+            } elseif ($this->isAutoBreak()) {
                 $this->addPageBreak($bodyNode);
             }
 
@@ -440,9 +535,6 @@ class Publisher
         }
 
         $this->publishEnd();
-
-        /* On renvoie le content dans le document */
-        $this->getDocument()->getArchive()->addFromString('content.xml', $this->outContent);
     }
 
 
@@ -511,4 +603,29 @@ class Publisher
     {
         return $this->outContent;
     }
+
+
+
+    /**
+     * @return bool
+     */
+    public function isPublished(): bool
+    {
+        return $this->published;
+    }
+
+
+
+    /**
+     * @param bool $published
+     *
+     * @return Publisher
+     */
+    public function setPublished(bool $published): Publisher
+    {
+        $this->published = $published;
+
+        return $this;
+    }
+
 }
\ No newline at end of file
diff --git a/src/Stylist.php b/src/Stylist.php
index 23a00e52a11a9fb7750e554a28ed5c3ab13eded3..60af3e102b5a0af1c1c3aace367de827b723eda7 100644
--- a/src/Stylist.php
+++ b/src/Stylist.php
@@ -237,23 +237,27 @@ class Stylist
 
     /**
      * @param DOMElement $element
-     * @param string     $value
+     * @param mixed      $value
      *
      * @return Publisher
      */
-    public function setVariable(DOMElement $element, string $value): Stylist
+    public function setVariable(DOMElement $element, $value): Stylist
     {
         $textNs = $this->getDocument()->getNamespaceUrl('text');
 
         $document = $element->ownerDocument;
 
-        $value = explode("\n", $value);
+        if (is_string($value) && false !== strpos($value, "\n")){
+            $value = explode("\n", $value);
+        }else{
+            $value = (array)$value;
+        }
         for ($i = 0; $i < count($value); $i++) {
             if ($i > 0) {
                 $returnVNode = $document->createElementNS($textNs, 'text:line-break');
                 $element->parentNode->insertBefore($returnVNode, $element);
             }
-            $vText = $document->createTextNode($value[$i]);
+            $vText = $document->createTextNode($this->getDocument()->formatValue($element->nodeValue, $value[$i]));
             $element->parentNode->insertBefore($vText, $element);
         }
         $element->parentNode->removeChild($element);