diff --git a/apps/maarch_entreprise/xml/config.xml.default b/apps/maarch_entreprise/xml/config.xml.default
index e1360e3fd96b82e51efc7422d5666fe4234b5676..847e06a6683b3c9a6ec66096512ccfc94e533ff4 100644
--- a/apps/maarch_entreprise/xml/config.xml.default
+++ b/apps/maarch_entreprise/xml/config.xml.default
@@ -299,4 +299,8 @@
         <moduleid>thesaurus</moduleid>
         <comment>_THESAURUS_COMMENT</comment>
     </MODULES>
+    <MODULES>
+        <moduleid>export_seda</moduleid>
+        <comment>_EXPORT_SEDA_COMMENT</comment>
+    </MODULES>
 </ROOT>
diff --git a/core/xml/actions_pages.xml b/core/xml/actions_pages.xml
index 0cb227b5e7ee65242e67e9c68b29c0d2585d7aab..705c6efa033c1184256ad5705a9777def341af39 100644
--- a/core/xml/actions_pages.xml
+++ b/core/xml/actions_pages.xml
@@ -291,4 +291,15 @@ An action page is described in a ACTIONPAGE tag :
             <COLL_ID>letterbox_coll</COLL_ID>
         </COLLECTIONS>
     </ACTIONPAGE>
+    <ACTIONPAGE>
+        <ID>export_seda</ID>
+        <LABEL>_EXPORT_SEDA</LABEL>
+        <NAME>export_seda</NAME>
+        <ORIGIN>module</ORIGIN>
+        <MODULE>export_seda</MODULE>
+        <FLAG_CREATE>false</FLAG_CREATE>
+        <COLLECTIONS>
+            <COLL_ID>letterbox_coll</COLL_ID>
+        </COLLECTIONS>
+    </ACTIONPAGE>
 </ROOT>
diff --git a/modules/export_seda/Acknowledgement.php b/modules/export_seda/Acknowledgement.php
new file mode 100644
index 0000000000000000000000000000000000000000..78bd517560357d4115bcadb8f66e066d31ae25a4
--- /dev/null
+++ b/modules/export_seda/Acknowledgement.php
@@ -0,0 +1,68 @@
+<?php
+
+/*
+*   Copyright 2008-2017 Maarch
+*
+*   This file is part of Maarch Framework.
+*
+*   Maarch Framework is free software: you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation, either version 3 of the License, or
+*   (at your option) any later version.
+*
+*   Maarch Framework is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with Maarch Framework.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+class Acknowledgement {
+
+	public function __construct()
+	{
+	}
+
+	public function send($fileName, $comments = "")
+	{
+		$xml = simplexml_load_file($fileName);
+		$messageObject = new stdClass();
+
+		if ($comments) {
+			$messageObject->comment = [];
+			if (is_array($comments)) {
+				foreach ($comments as $comment) {
+					$messageObject->comment[] = $comment;
+				}
+			} else {
+				$messageObject->comment[] = $comments;
+			}
+		}
+		
+		$messageIdentifier = (string) $xml->MessageIdentifier;
+		$messageObject->date = date('Y-m-d h:i:s');
+		$messageObject->messageIdentifier =  $messageIdentifier . "_Acknowledgement";
+		//$messageObject->signature =  "";
+		$messageObject->messageReceivedIdentifier = $messageIdentifier;
+		$messageObject->sender = $xml->ArchivalAgency->Identifier;
+		$messageObject->receiver = $xml->TransferringAgency->Identifier;
+
+		$this->sendXml($messageObject);
+	}
+
+	public function sendXml($messageObject)
+	{
+		$DOMTemplate = new DOMDocument();
+		$DOMTemplate->load(__DIR__.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'Acknowledgement.xml');
+		$DOMTemplateProcessor = new DOMTemplateProcessor($DOMTemplate);
+		$DOMTemplateProcessor->setSource('Acknowledgement', $messageObject);
+		$DOMTemplateProcessor->merge();
+		$DOMTemplateProcessor->removeEmptyNodes();
+
+        file_put_contents(__DIR__.DIRECTORY_SEPARATOR.'seda2'.DIRECTORY_SEPARATOR.$messageObject->messageReceivedIdentifier.'_Acknowledgement.xml', $DOMTemplate->saveXML());
+
+		return $xml;
+	}
+}
\ No newline at end of file
diff --git a/modules/export_seda/ArchiveTransfer.php b/modules/export_seda/ArchiveTransfer.php
new file mode 100644
index 0000000000000000000000000000000000000000..a50950a80a5facc63dd617a449b2318d97fe5784
--- /dev/null
+++ b/modules/export_seda/ArchiveTransfer.php
@@ -0,0 +1,392 @@
+<?php
+
+/*
+*   Copyright 2008-2017 Maarch
+*
+*   This file is part of Maarch Framework.
+*
+*   Maarch Framework is free software: you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation, either version 3 of the License, or
+*   (at your option) any later version.
+*
+*   Maarch Framework is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with Maarch Framework.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+require_once 'core/class/class_request.php';
+require_once __DIR__.'/DOMTemplateProcessor.php';
+
+class ArchiveTransfer {
+
+	private $db;
+
+	public function __construct() 
+	{
+		$this->db = new Database();
+	}
+
+	public function receive($listResId, $transferringAgency = "", $archivalAgency = "") {
+		
+		if (!$listResId) {
+			return false;
+		}
+
+		$messageObject = new stdClass();
+		$messageObject = $this->initMessage($messageObject, $transferringAgency, $archivalAgency);
+
+		foreach ($listResId as $resId) {
+			$letterbox = $this->getCourrier($resId);
+
+			if ($letterbox->filename) {
+				$messageObject->dataObjectPackage->descriptiveMetadata->archiveUnit[] = $this->getArchiveUnit($letterbox);
+				$messageObject->dataObjectPackage->binaryDataObject[] = $this->getBinaryDataObject($letterbox);
+			} else {
+				$messageObject->dataObjectPackage->descriptiveMetadata->archiveUnit[] = $this->getArchiveUnit($letterbox);
+			}
+		}
+
+		//TODO
+		//$messageObject->dataObjectPackage->managementMetadata
+		
+		$this->insertMessage($messageObject);
+		return $messageObject;
+	}
+
+	public function sendXml($messageObject)
+	{
+		$DOMTemplate = new DOMDocument();
+		$DOMTemplate->load(__DIR__.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'ArchiveTransfer.xml');
+		$DOMTemplateProcessor = new DOMTemplateProcessor($DOMTemplate);
+		$DOMTemplateProcessor->setSource('ArchiveTransfer', $messageObject);
+		$DOMTemplateProcessor->merge();
+		$DOMTemplateProcessor->removeEmptyNodes();
+
+        file_put_contents(__DIR__.DIRECTORY_SEPARATOR.'seda2'.DIRECTORY_SEPARATOR.$messageObject->messageIdentifier->value.'.xml', $DOMTemplate->saveXML());
+
+		return $xml;
+	}
+
+	private function initMessage($messageObject, $transferringAgency =null, $archivalAgency = null)
+	{
+		$messageObject->date = date('Y-m-d h:i:s');
+		$messageObject->messageIdentifier = new stdClass();
+		$messageObject->messageIdentifier->value = $_SESSION['user']['UserId'] . "-" . date('Ymd-His');
+
+		$messageObject->transferringAgency = new stdClass();
+		$messageObject->transferringAgency->identifier = new stdClass();
+
+		if ($transferringAgency) {
+			$messageObject->transferringAgency->identifier->value = $transferringAgency;
+		}else {
+			foreach ($_SESSION['user']['entities'] as $entitie) {
+				if ($entitie['ENTITY_TYPE'] == "Service") {
+					$entitie = $this->getEntitie($entitie['ENTITY_ID']);
+					if ($entitie) {
+						$messageObject->transferringAgency->identifier->value = $entitie->business_id;
+					} else {
+						// TODO return error;
+					}
+				}
+			}
+		}
+
+		$messageObject->archivalAgreement = new stdClass();
+		$messageObject->archivalAgreement->value = "A COMPLETER";
+
+		$messageObject->archivalAgency = new stdClass();
+		$messageObject->archivalAgency->identifier = new stdClass();
+
+		if ($archivalAgency) {
+			$messageObject->archivalAgency->identifier->value = $archivalAgency;
+		} else {
+			$messageObject->archivalAgency->identifier->value = "A COMPLETER";
+		}
+		
+		$messageObject->dataObjectPackage = new stdClass();
+		$messageObject->dataObjectPackage->binaryDataObject = [];
+		$messageObject->dataObjectPackage->descriptiveMetadata = new stdClass();
+		$messageObject->dataObjectPackage->managementMetadata = new stdClass();
+		$messageObject->dataObjectPackage->descriptiveMetadata->archiveUnit = [];
+
+		return $messageObject;
+	}
+
+	private function getArchiveUnit($letterbox)
+	{
+		$messageArchiveUnit = new stdClass();
+
+		$messageArchiveUnit->content = new stdClass();
+		$messageArchiveUnit->content->receivedDate = $letterbox->admission_date;
+		$messageArchiveUnit->content->sentDate = $letterbox->doc_date;
+		$messageArchiveUnit->content->receivedDate = $letterbox->admission_date;
+		$messageArchiveUnit->content->receivedDate = $letterbox->admission_date;
+
+		$messageArchiveUnit->content->addressee = [];
+		$messageArchiveUnit->content->keyword = [];
+
+		if ($letterbox->exp_contact_id) {
+			
+			$contact = $this->getContact($letterbox->exp_contact_id);
+			$entitie = $this->getEntitie($letterbox->destination);
+
+			$messageArchiveUnit->content->keyword[] = $this->getKeyword($contact);
+			$messageArchiveUnit->content->addressee[] = $this->getAddresse($entitie,"entitie");
+		} else if ($letterbox->dest_contact_id) {
+			$contact = $this->getContact($letterbox->dest_contact_id);
+			$entitie = $this->getEntitie($letterbox->destination);
+
+			$messageArchiveUnit->content->addressee[] = $this->getAddresse($contact);
+			$messageArchiveUnit->content->keyword[] = $this->getKeyword($entitie,"entitie");
+		} else if ($letterbox->exp_user_id) {
+			$user = $this->getUserInformation($letterbox->exp_user_id);
+			$entitie = $this->getEntitie($letterbox->initiator);
+			//$entitie = $this->getEntitie($letterbox->destination);
+
+			$messageArchiveUnit->content->keyword[] = $this->getKeyword($user);
+			$messageArchiveUnit->content->addressee[] = $this->getAddresse($entitie,"entitie");
+		}
+		
+		$messageArchiveUnit->content->source = $_SESSION['mail_nature'][$letterbox->nature_id];
+
+		$messageArchiveUnit->content->documentType = $letterbox->type_label;
+		$messageArchiveUnit->content->originatingAgencyArchiveIdentifier = $letterbox->alt_identifier;
+		$messageArchiveUnit->content->originatingSystemId = $letterbox->res_id;
+		$messageArchiveUnit->content->title = [];
+		$messageArchiveUnit->content->title[] = $letterbox->subject;
+		$messageArchiveUnit->content->description = [];
+		$messageArchiveUnit->content->description[] = " ";
+		$messageArchiveUnit->content->endDate = $letterbox->process_limit_date;
+
+		$notes = $this->getNotes($letterbox->res_id);
+		$messageArchiveUnit->content->custodialHistory = new stdClass();
+		$messageArchiveUnit->content->custodialHistory->custodialHistoryItem = [];
+
+		foreach ($notes as $note) {
+			$messageArchiveUnit->content->custodialHistory->custodialHistoryItem[] = $this->getCustodialHistoryItem($note);
+		}
+
+		if ($dataObjectReferenceId) {
+			$messageArchiveUnit->dataObjectReference = new stdClass();
+			$messageArchiveUnit->dataObjectReference->dataObjectReferenceId = $letterbox->res_id;
+		}
+
+		return $messageArchiveUnit;
+	}
+
+	private function getBinaryDataObject($letterbox)
+	{
+		$binaryDataObject = new stdClass();
+		$binaryDataObject->id = $letterbox->res_id;
+		$binaryDataObject->messageDigest = new stdClass();
+		$binaryDataObject->messageDigest->value = $letterbox->fingerprint;
+
+		$binaryDataObject->size = new stdClass();
+		$binaryDataObject->size->value = $letterbox->filesize;
+
+		$uri = str_replace("##", DIRECTORY_SEPARATOR, $letterbox->path);
+		$uri =  str_replace("#", DIRECTORY_SEPARATOR, $uri);
+		$uri .= $letterbox->filename;
+		$binaryDataObject->uri = $uri;
+
+		return $binaryDataObject;
+	}
+
+	private function getKeyword($informations, $type = null)
+	{
+		$keyword = new stdClass();
+		$keyword->keywordContent = new stdClass();
+
+		if ($type == "entitie") {
+			$keyword->keywordType = "corpname";
+			$keyword->keywordContent = $informations->business_id;
+		} else if ($informations->is_corporate_person == "Y") {
+			$keyword->keywordType = "corpname";
+			$keyword->keywordContent->value = $informations->society;
+		} else {
+			$keyword->keywordType = "personname";
+			$keyword->keywordContent->value = $informations->lastname . " " . $informations->firstname;
+		}
+
+		return $keyword;
+	}
+
+	private function getAddresse($informations, $type = null)
+	{
+		$addressee = new stdClass();
+		if ($type == "entitie") {
+			$addressee->corpname = $informations->entity_label;
+			$addressee->identifier = $informations->business_id;
+		} else if ($informations->is_corporate_person == "Y") {
+			$addressee->corpname = $informations->society;
+			$addressee->identifier = $informations->contact_id;
+		} else {
+			$addressee->firstName = $informations->firstname;
+			$addressee->birthName = $informations->lastname;
+		}
+			
+
+		return $addressee;
+	}
+
+	private function getCustodialHistoryItem($note) 
+	{
+		$custodialHistoryItem = new stdClass();
+
+		$custodialHistoryItem->value = $note->note_text;
+		$custodialHistoryItem->when = $note->date_note;
+
+		return $custodialHistoryItem;
+	}
+
+	private function getCourrier($resId) 
+	{
+		$queryParams = [];
+
+		$queryParams[] = $resId;
+
+		$query = "SELECT * FROM res_view_letterbox WHERE res_id = ?";
+
+		$smtp = $this->db->query($query,$queryParams);
+		
+		$letterbox = $smtp->fetchObject();
+
+		return $letterbox;
+	}
+
+	private function getUserInformation($userId) 
+	{
+		$queryParams = [];
+
+		$queryParams[] = $userId;
+
+		$query = "SELECT * FROM users WHERE user_id = ?";
+
+		$smtp = $this->db->query($query,$queryParams);
+		
+		$user = $smtp->fetchObject();
+
+		return $user;
+	}
+
+	private function getNotes($letterboxId) 
+	{
+		$queryParams = [];
+
+		$queryParams[] = $letterboxId;
+
+		$query = "SELECT * FROM notes WHERE identifier = ?";
+
+		$smtp = $this->db->query($query,$queryParams);
+
+		$notes = [];
+		while ($res = $smtp->fetchObject()) {
+			$notes[] = $res;
+		}
+
+		return $notes;
+	}
+
+	private function getEntitie($entityId)
+	{
+		$queryParams = [];
+
+		$queryParams[] = $entityId;
+
+		$query = "SELECT * FROM entities WHERE entity_id = ?";
+
+		$smtp = $this->db->query($query,$queryParams);
+		
+		$entitie = $smtp->fetchObject();
+
+		return $entitie;
+	}
+
+	private function getContact($contactId)
+	{
+		$queryParams = [];
+
+		$queryParams[] = $contactId;
+
+		$query = "SELECT * FROM contacts_v2 WHERE contact_id = ?";
+
+		$smtp = $this->db->query($query,$queryParams);
+		
+		$contact = $smtp->fetchObject();
+
+		return $contact;
+	}
+
+	private function insertMessage($messageObject) 
+	{
+		$queryParams = [];
+		$messageId = uniqid();
+
+		try {
+			$query = ("INSERT INTO seda (
+				message_id,
+				schema,
+				type,
+				status,
+				date,
+				reference,
+	            account_id ,
+				sender_org_identifier_id,
+				sender_org_name,
+				recipient_org_identifier_id,
+				recipient_org_name,
+				archival_agreement_reference,
+				reply_code,
+				size,
+				data,
+				active,
+				archived)
+				VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
+
+			$queryParams[] = $messageId; // Message Id
+			$queryParams[] = "2.1"; //Schema
+			$queryParams[] = "ArchiveTransfer"; // Type
+			$queryParams[] = "sent"; // Status
+			$queryParams[] = $messageObject->date; // Date
+			$queryParams[] = $messageObject->messageIdentifier->value; // Reference
+			$queryParams[] = $_SESSION['user']['UserId']; // Account Id
+			$queryParams[] = $messageObject->transferringAgency->identifier->value; // Sender org identifier id
+			$queryParams[] = ""; //SenderOrgNAme
+			$queryParams[] = $messageObject->archivalAgency->identifier->value; // Recipient org identifier id
+			$queryParams[] = ""; //RecipientOrgNAme
+			$queryParams[] = $messageObject->archivalAgreement->value; // Archival agreement reference
+			$queryParams[] = ""; //ReplyCode
+			$queryParams[] = 0; // size
+			$queryParams[] = ""; // Data
+			$queryParams[] = 1; // active
+			$queryParams[] = 0; // archived
+
+			$res = $this->db->query($query,$queryParams);
+
+			//var_dump($messageObject);
+			foreach ($messageObject->dataObjectPackage->binaryDataObject as $binaryDataObject) {
+				$this->insertUnitIdentifier($messageId, "res_letterbox", $binaryDataObject->id);
+			}
+		} catch (Exception $e) {
+			// return error
+		}
+	}
+
+	private function insertUnitIdentifier($messageId, $tableName, $resId) {
+		$query = ("INSERT INTO unit_identifier VALUES (?,?,?)");
+		$queryParams = [];
+
+		$queryParams[] = $messageId;
+		$queryParams[] = $tableName;
+		$queryParams[] = $resId;
+
+		$res = $this->db->query($query,$queryParams);
+
+		return $res;
+	}
+}
\ No newline at end of file
diff --git a/modules/export_seda/ArchiveTransferReply.php b/modules/export_seda/ArchiveTransferReply.php
new file mode 100644
index 0000000000000000000000000000000000000000..617fa748e434819fd5ef215a0a84d097c2db2fe8
--- /dev/null
+++ b/modules/export_seda/ArchiveTransferReply.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+*   Copyright 2008-2017 Maarch
+*
+*   This file is part of Maarch Framework.
+*
+*   Maarch Framework is free software: you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation, either version 3 of the License, or
+*   (at your option) any later version.
+*
+*   Maarch Framework is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with Maarch Framework.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+require_once 'core/class/class_request.php';
+
+class ArchiveTransfertReply {
+
+	public function __construct() 
+	{
+		$this->db = new Database();
+	}
+
+	public function receive($fileName) {
+
+		$xml = simplexml_load_file($fileName);
+
+		$message = new stdClass();
+		$message->reference = $xml->MessageRequestIdentifier;
+		$message->status = "receive";
+		$message->replyCode = $xml->DataObjectPackage->ReplyCode;
+		$message->operationDate = (string) $xml->DataObjectPackage->GrantDate;
+		$message->replyReference = (string) $xml->MessageIdentifier;
+		$message->comment = $xml->comment;
+
+		$this->updateMessage($message);
+	}
+
+	private function updateMessage($message) 
+	{
+		$queryParams = [];
+
+		try {
+			$query = ("UPDATE seda SET status = ?, reply_code = ?, operation_date = ?, reply_reference = ?  WHERE reference = ?");
+
+			$queryParams[] = $message->status; 
+			$queryParams[] = $message->replyCode;
+			$queryParams[] = $message->operationDate; 
+			$queryParams[] = $message->replyReference; 
+			$queryParams[] = $message->reference;
+
+			$this->db->query($query,$queryParams);
+
+		} catch (Exception $e) {
+			var_dump($e);
+		}
+	}
+}
\ No newline at end of file
diff --git a/modules/export_seda/DOMTemplateProcessor.php b/modules/export_seda/DOMTemplateProcessor.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6206cfb322d75d4cc29cd724d20afcc582c4176
--- /dev/null
+++ b/modules/export_seda/DOMTemplateProcessor.php
@@ -0,0 +1,1235 @@
+<?php
+/*
+ * Copyright (C) 2015 Maarch
+ *
+ * This file is part of dependency xml.
+ *
+ * Dependency xml is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dependency xml is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with dependency xml.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Process DOM XML Template documents
+ * 
+ * @author Cyril Vazquez <cyril.vazquez@maarch.org>
+ */
+class DOMTemplateProcessor
+    extends \DOMXPath
+{
+    /**
+     * The array of parsed processing instructions
+     * @var array
+     */
+    protected $parsedPis = array();
+
+    /**
+     * The array of parsed text instructions
+     * @var array
+     */
+    protected $parsedTexts = array();
+
+    /**
+     * The storage of already merged nodes
+     * @var array
+     */
+    protected $mergedNodes;
+
+    /**
+     * The storage of already merged form nodes
+     * @var array
+     */
+    protected $mergedForms;
+
+    /**
+     * The data sources
+     * @var array
+     */
+    protected $sources = array();
+
+    /**
+     * The variables
+     * @var array
+     */
+    protected $variables = array();
+
+    /**
+     * Constructor
+     * @param DOMDocument $document
+     */
+    public function __construct($document)
+    {
+        parent::__construct($document);
+
+        
+        $this->xinclude();
+        $this->xinclude();
+        $this->xinclude();
+        $this->mergedNodes = new \SplObjectStorage();
+        $this->mergedForms = new \SplObjectStorage();
+
+        $this->bindVariable("_SESSION", $_SESSION);
+        $this->bindVariable("_SERVER", $_SERVER);
+        $this->bindVariable("_GET", $_GET);
+        $this->bindVariable("_POST", $_POST);
+        $this->bindVariable("_ENV", $_ENV);
+        $this->bindVariable("_FILES", $_FILES);
+    }
+
+    /**
+     * Process xinclude processing instructions
+     * @param DOMNode $node The context node. If omitted the method processes the entire document tree.
+     */
+    protected function xinclude($node=null)
+    {
+        if ($pis = $this->query("descendant-or-self::processing-instruction('xinclude')", $node)) {
+            foreach ($pis as $pi) {
+                $includeFragment = $this->document->createDocumentFragment();
+                $source = file_get_contents(__DIR__.trim($pi->data));
+                if (!$source) {
+                    throw new \Exception("Error including Xml fragment: fragment '$pi->data' could not be parsed");
+                }
+
+                $includeFragment->appendXML($source);
+
+                $pi->parentNode->replaceChild($includeFragment, $pi);
+            }
+        }
+    }
+
+    /**
+     * Bind a variable
+     * @param string $name      The name of the variable
+     * @param string &$variable The reference of the value
+     */
+    public function bindVariable($name, &$variable)
+    {
+        $this->variables[$name] = &$variable;
+    }
+
+    /**
+     * Set a source for merge
+     * @param string $name  The name of the data source
+     * @param string $value The value
+     */
+    public function setSource($name, $value)
+    {
+        $this->sources[$name] = $value;
+    }
+
+    /**
+     * Remove empty elements and attributes
+     * @param DOMNode $node The context node. If omitted the entire document will be processed.
+     */
+    public function removeEmptyNodes($node=null)
+    {
+        if (!$node) {
+            $node = $this->document->documentElement;
+        }
+
+        switch($node->nodeType) {
+            case \XML_ELEMENT_NODE:
+                $childNodeList = $node->childNodes;
+                for ($i=0, $l=$childNodeList->length; $i<$l; $i++) {
+                    $this->removeEmptyNodes($childNodeList->item($i));
+                }
+
+                $childNodeList = $node->childNodes;
+                if ($childNodeList->length == 0 && !$node->hasAttributes()) {
+                    $node->parentNode->removeChild($node);
+                }
+                break;
+
+            case \XML_ATTRIBUTE_NODE:
+                if (empty($node->value)) {
+                    $node->parentNode->removeChild($node);
+                }
+                break;
+
+            case \XML_TEXT_NODE:
+                if (ctype_space($node->nodeValue) && $node->previousSibling && $node->previousSibling->nodeType == \XML_TEXT_NODE) {
+                    $node->nodeValue = trim($node->nodeValue);
+                }
+                break;
+        }
+    }
+
+    /* -------------------------------------------------------------------------
+    - MERGE processing instructions
+    ------------------------------------------------------------------------- */
+    /**
+     * Merges the processing instructions on the given node and its chil nodes.
+     * 
+     * @param string $node   The context node. If omitted the entire document will be processed.
+     * @param string $source The data source. If omitted, all merge instruction path must be existing sources
+     */
+    public function merge($node=null, $source=null)
+    {
+        // Avoid garbage nodes merge
+        if (!isset($this->mergedNodes)) {
+            $this->mergedNodes = new \SplObjectStorage();
+        }
+
+        if (!isset($this->mergedForms)) {
+            $this->mergedForms = new \SplObjectStorage();
+        }
+        
+        if ($node && $this->mergedNodes->contains($node)) {
+            return;
+        }
+
+        $mergeNodes = $this->query("descendant-or-self::processing-instruction('merge') | descendant-or-self::text()[contains(., '[?merge')] | descendant-or-self::*/@*[contains(., '[?merge')]", $node);
+
+        $this->mergedObjects = array();
+
+        foreach ($mergeNodes as $i => $mergeNode) {
+            switch ($mergeNode->nodeType) {
+                case XML_PI_NODE :
+                    if (!isset($this->parsedPis[$mergeNode->data])) {
+                        $this->parsedPis[$mergeNode->data] = $this->parse($mergeNode->data);
+                    }
+                    $instr = $this->parsedPis[$mergeNode->data];
+
+                    if ($merged = $this->mergePi($mergeNode, $instr, $source)) {
+                        if ($mergeNode->parentNode) {
+                            $mergeNode->parentNode->removeChild($mergeNode);
+                        }
+                    }
+                    break;
+
+                case XML_TEXT_NODE:
+                case XML_ELEMENT_NODE:
+                case XML_ATTRIBUTE_NODE:
+                default:
+                    $this->mergeTextNode($mergeNode, $source);
+            }
+        }
+
+        /*$this->mergePis($node, $source);
+
+        $this->mergeTextNodes($node, $source);*/
+
+        $this->mergeForms();
+
+        if ($node) {
+            $this->mergedNodes->attach($node);
+        }
+    }
+
+    protected function mergePi($pi, $instr, $source=null)
+    {
+        // Get value by reference
+        $value = &$this->getData($instr, $source);
+
+        // Use value with selected target
+        if (isset($instr->params['var'])) {
+            $this->addVar($instr->params['var'], $value);
+            
+            $pi->parentNode->removeChild($pi);
+
+            return false;
+        }
+
+        // Get type of value
+        $type = gettype($value);
+        //var_dump($type);
+        //if (isset($instr->params['source']))
+        //    var_dump($instr->params['source']);
+
+        switch(true) {
+            // If value is scalar, merge text before Pi
+            case $type == 'string':
+            case $type == 'integer':
+            case $type == 'double':
+                return $this->mergeText($pi, $instr, $value);
+
+            // Value is bool, remove target sibling if false
+            case $type == 'boolean':
+                return $this->mergeBool($pi, $instr, $value);
+
+            // Value is null, no action
+            case $type == 'NULL':
+                return true;
+
+            // Value is array, merge target by iterating over array
+            case $type == 'array':
+                return $this->mergeArray($pi, $instr, $value);
+
+            case $type == 'object' :
+                switch (true) {
+                    // Object merged with a form
+                    case ($targetForm = $this->query("following-sibling::form", $pi)->item(0)) :
+                        $this->mergedForms->attach($targetForm, array($pi, $instr, $value));
+                        break;
+
+                    // ArrayObject -> merge array
+                    case ($value instanceof \ArrayAccess && $value instanceof \Iterator) :
+                        return $this->mergeArray($pi, $instr, $value);
+
+                    // DOMNode -> merge as xml
+                    case $value instanceof \DOMNode :
+                        return $this->mergeNode($pi, $instr, $value);
+
+                    // If value is an object but no form : merge string version if possible
+                    case method_exists($value, '__toString'):
+                        return $this->mergeText($pi, $instr, (string) $value);                    
+                }
+
+        }
+
+    }
+
+    protected function addVar($name, &$var)
+    {
+        $this->variables[$name] = $var;
+    }
+
+    protected function mergeForms()
+    {
+        $this->mergedForms->rewind();
+        while ($this->mergedForms->valid()) {
+            $index  = $this->mergedForms->key();
+            $targetForm = $this->mergedForms->current();
+            list($pi, $instr, $object) = $this->mergedForms->getInfo();
+
+            $params = $instr->params;
+
+            if (isset($params['source'])) {
+                $this->setSource($params['source'], $object);
+            }
+
+            $this->mergeObjectProperties($targetForm, $object, $params, $oname = false);
+
+            //$pi->parentNode->removeChild($pi);
+
+            $this->mergedForms->next();
+        }
+    }
+
+    protected function mergeTextNodes($node=null, $source=null)
+    {
+        $textNodes = $this->query("descendant-or-self::text()[contains(., '[?merge')] | descendant-or-self::*/@*[contains(., '[?merge')]", $node);
+
+        for ($i=0, $l=$textNodes->length; $i<$l; $i++) {
+            $textNode = $textNodes->item($i);
+            $this->mergeTextNode($textNode, $source);
+        }
+    }
+
+    protected function mergeTextNode($textNode, $source=null)
+    {
+        //$nodeXml = $this->saveXml($textNode);
+        $nodeValue = $textNode->nodeValue;
+        if (isset($this->parsedTexts[$nodeValue])) {
+            $instructions = $this->parsedTexts[$nodeValue];
+        } else {
+            preg_match_all("#(?<pi>\[\?merge (?<instr>(?:(?!\?\]).)*)\?\])#", $nodeValue, $pis, PREG_SET_ORDER);
+            $instructions = array();
+            foreach ($pis as $i => $pi) {
+                $instructions[$pi['pi']] = $this->parse($pi['instr']);
+            }
+            $this->parsedTexts[$nodeValue] = $instructions;
+        }
+
+        foreach ($instructions as $pi => $instr) {
+            $value = $this->getData($instr, $source);
+            if (is_scalar($value) || is_null($value) || (is_object($value) && method_exists($value, '__toString'))) {
+                $mergedValue = str_replace($pi, (string) $value, $textNode->nodeValue);
+                $mergedValue = htmlentities($mergedValue);
+                $textNode->nodeValue = str_replace($pi, $value, $mergedValue);
+            }
+        }
+
+        // If text is in an attribute that is empty, remove attribute
+        if ($textNode->nodeType == XML_ATTRIBUTE_NODE && empty($textNode->value)) {
+            $textNode->parentNode->removeAttribute($textNode->name);
+        }
+    }
+
+    protected function mergeText($pi, $instr, $value)
+    {
+        $params = $instr->params;
+        switch(true) {
+        case isset($params['attr']):
+            if (!$targetNode = $this->query("following-sibling::*", $pi)->item(0)) {
+                return true;
+            }
+            $targetNode->setAttribute($params['attr'], $value);
+            break;
+
+        case isset($params['render']):
+            if (!$params['render']) {
+                $fragment = $value;
+            } else { 
+                $fragment = $params['render'];
+            }
+            if (!isset($this->fragments[$fragment])) {
+                return true;
+            }
+            $targetNode = $this->fragments[$fragment]->cloneNode(true);
+            $this->merge($targetNode);
+            $pi->parentNode->insertBefore($targetNode, $pi);
+            break;
+
+        default:
+            $targetNode = $this->document->createTextNode($value);
+            $pi->parentNode->insertBefore($targetNode, $pi);
+        }
+
+        return true;
+    }
+
+    protected function mergeArray($pi, $instr, &$array)
+    {
+        $params = $instr->params;
+
+        if (isset($params['include'])) {
+            $filename = $params['include'];
+            $source = file_get_contents($filename);
+
+            $targetNode = $this->document->createDocumentFragment();
+            $targetNode->appendXML($source);
+
+        } elseif (!$targetNode = $this->query("following-sibling::*", $pi)->item(0)) {
+            return true;
+        }
+
+        reset($array);
+        if ($count = count($array)) {
+            $i=0;
+            while ($i<$count) {
+            //do {
+                $itemNode = $targetNode->cloneNode(true);
+                $itemData = current($array);
+                if (isset($params['source'])) {
+                    $this->setSource($params['source'], $itemData);
+                }
+
+                $this->merge($itemNode, $itemData);
+                $pi->parentNode->insertBefore($itemNode, $pi);
+
+                @next($array);
+                $i++;
+            /*} while (
+                @next($array) !== false
+            );*/
+            }
+        }
+        // Remove targetNode (row template)
+        if ($targetNode->parentNode) {
+            $targetNode = $targetNode->parentNode->removeChild($targetNode);
+        }
+
+        // Add to mergedNodes to prevent other calls to merge
+        $this->mergedNodes->attach($targetNode);
+
+        return true;
+    }
+
+    protected function mergeObject($pi, $instr, $object)
+    {
+        $params = $instr->params;
+        if (!$targetNode = $this->query("following-sibling::*", $pi)->item(0)) {
+            return true;
+        }
+
+        if (isset($params['source'])) {
+            $this->setSource($params['source'], $object);
+        }
+
+        $this->mergeObjectProperties($targetNode, $object, $params, $oname = false);
+
+        return true;
+    }
+
+    protected function mergeObjectProperties($targetNode, $object, $params, $oname=false)
+    {
+        foreach ($object as $pname => $pvalue) {
+            if ($oname) {
+                $pname = $oname . "." . $pname;
+            }
+            //var_dump("merge $pname");
+            if (is_scalar($pvalue) || (is_object($pvalue) && method_exists($pvalue, '__toString'))) {
+                $this->mergeObjectProperty($targetNode, $pvalue, $params, $pname);
+            }
+            /*elseif (is_object($pvalue))
+                $this->mergeObjectProperties($targetNode, $pvalue, $params, $pname);
+            elseif (is_array($pvalue))
+                foreach ($pvalue as $key => $item)
+                    $this->mergeObjectProperties($targetNode, $pvalue, $params, $pname . "[$key]");*/
+        }
+    }
+
+    protected function mergeObjectProperty($targetNode, $value, $params, $name)
+    {
+        $elements = $this->query("descendant-or-self::*[@name='$name']", $targetNode);
+        for ($i=0, $l=$elements->length; $i<$l; $i++) {
+            $element = $elements->item($i);
+            switch (strtolower($element->nodeName)) {
+                // Form Input
+                case 'input':
+                    switch($element->getAttribute('type')) {
+                        case 'checkbox':
+                            if (is_bool($value)) {
+                                if ($value) {
+                                    $element->setAttribute('checked', 'true');
+                                } else {
+                                    $element->removeAttribute('checked');
+                                }
+                            } else {
+                                if ($element->getAttribute('value') == $value) {
+                                    $element->setAttribute('checked', 'true');
+                                } else {
+                                    $element->removeAttribute('checked');
+                                }
+                            }
+                            
+                            break;
+
+                        case 'radio':
+                            if ($element->getAttribute('value') == $value) {
+                                $element->setAttribute('checked', 'true');
+                            } else {
+                                $element->removeAttribute('checked');
+                            }
+                            break;
+
+                        default:
+                            $element->setAttribute('value', $value);
+                    }
+                    break;
+
+                // Select
+                case 'select':
+                    $value = $this->quote($value);
+                    if ($option = $this->query(".//option[@value=".$value."]", $element)->item(0)) {
+                        $option->setAttribute('selected', 'true');
+                        if ($optGroup = $this->query("parent::optgroup", $option)->item(0)) {
+                            $optGroup->removeAttribute('disabled');
+                        }
+                    }
+                    break;
+
+                // Textareas
+                case 'textarea':
+                    $element->nodeValue = $value;
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Merge a boolean
+     * @param DOMNode $pi
+     * @param string  $instr
+     * @param boolean $bool
+     * 
+     * @return bool
+     */
+    protected function mergeBool($pi, $instr, $bool)
+    { 
+        $params = $instr->params;
+        if (isset($params['include'])) {
+            $res = $params['include'];
+            $targetNode = $this->document->createDocumentFragment();
+        } elseif (!$targetNode = $this->query("following-sibling::*", $pi)->item(0)) {
+            return true;
+        }
+
+        if (isset($params['attr'])) {
+            if ($bool == false) {
+                $targetNode->removeAttribute($params['attr']);
+            } else {
+                $targetNode->setAttribute($params['attr'], $params['attr']);
+            }
+        } else {
+            if (isset($params['source'])) {
+                $this->setSource($params['source'], $bool);
+            }
+            if ($bool == false) {
+                if ($targetNode->parentNode) {
+                    $parentNode = $targetNode->parentNode;
+                    $targetNode = $parentNode->removeChild($targetNode);
+                }
+
+                // Add to mergedNodes to prevent other calls to merge
+                $this->mergedNodes->attach($targetNode);
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Merge a node
+     * @param DOMNode $pi
+     * @param string  $instr
+     * @param DOMNode $DOMNode
+     * 
+     * @return bool
+     */
+    public function mergeNode($pi, $instr, $DOMNode)
+    {
+        $pi->parentNode->insertBefore($DOMNode, $pi);
+
+        return true;
+    }
+
+    /* ------------------------------------------------------------------------
+        Data sources management
+    ------------------------------------------------------------------------ */
+    protected function &getData($instr, $source=null)
+    {
+        //var_dump("getData");
+        //var_dump($instr);
+        //var_dump($source);
+
+        $value = null;
+
+        $steps = $instr->source;
+
+        // First step defines source
+        $type = $steps[0][0];
+        switch($type) {
+            case 'arg':
+                $value = &$source;
+                break;
+            case 'source':
+                $name = $steps[0][1];
+                if (isset($this->sources[$name])) {
+                    $value = &$this->sources[$name];
+                } elseif (is_scalar($name)) {
+                    if ($name[0] == '"' || $name[0] == "'") {
+                        $value = substr($name, 1, -1);
+                    } elseif (is_numeric($name)) {
+                        $value = $name;
+                    }
+                }
+                break;
+            case 'var':
+                $name = $steps[0][1];
+                if (isset($this->variables[$name])) {
+                    $value = &$this->variables[$name];
+                }
+                break;
+            case 'method':
+                $route = $steps[0][1];
+                $methodRouter = new \core\Route\MethodRouter($route);
+                $serviceObject = $methodRouter->service->newInstance();
+                break;
+        }
+
+        for ($i=1, $l=count($steps); $i<$l; $i++) {
+            $value = &$this->stepData($steps[$i], $value);
+        }
+
+        return $value;
+    }
+
+    protected function &stepData($step, $source)
+    {
+        //var_dump("stepData");
+        //var_dump($step);
+        //var_dump("from " . gettype($source));
+        $value = null;
+        switch($step[0]) {
+        case 'func':
+            $value = &$this->stepFunc($step[1], $step[2], $source);
+            break;
+
+        case 'offset':
+            $key = &$this->getParamValue($step[1], $source);
+            if (is_array($source) && isset($source[$key])) {
+                $value = &$source[$key];
+            }
+            break;
+
+        case 'prop':
+            if (isset($source->{$step[1]})) {
+                $value = &$source->{$step[1]};
+            }
+            break;
+        }
+        
+        return $value;
+    }
+
+    protected function &stepFunc($name, $params=array(), $source=null)
+    {
+        $value = null;
+        foreach ($params as $i => $param) {
+            $params[$i] = &$this->getParamValue($param, $source);
+        }
+
+        if (is_object($source) && method_exists($source, $name)) {
+            $value = call_user_func_array(array($source, $name), $params);
+
+            return $value;
+        }
+        //var_dump($params);
+        switch($name) {
+            // Callback functions
+            case 'func':
+                $func = $params[0];
+                if (!isset($this->functions[$func])) {
+                    break;
+                }
+                $callback = $this->functions[$func];
+                array_unshift($params, $source);
+                array_unshift($params, $this);
+                $value = @call_user_func_array($callback, $params);
+                break;
+
+            // Array functions
+            case 'length':
+            case 'count':
+                $value = @count($source);
+                break;
+            case 'key':
+                $value = @key($source);
+                break;
+            case 'current':
+                $value = @current($source);
+                break;
+            case 'first':
+                $value = @reset($source);
+                break;
+            case 'next':
+                $value = @next($source);
+                break;
+            case 'prev':
+                $value = @prev($source);
+                break;
+            case 'end':
+                $value = @end($source);
+                break;
+            case 'pos':
+                $pos = null;
+                foreach ((array) $source as $key => $value) {
+                    $pos++;
+                    if ($key == @key($source)) {
+                        break;
+                    }
+                }
+                if (!is_null($pos)) {
+                    $value = $pos;
+                }
+                break;
+            case 'islast':
+                $value = ((@key($source)+1) == @count($source));
+                break;
+            case 'slice':
+                $value = @array_slice($source, $params[0], $params[1]);
+                break;
+            case 'arraykeyexists':
+                $value = @array_key_exists($params[0], $source);
+                break;
+            case 'inarray':
+                $value = @in_array($params[0], $source);
+                break;
+
+            // Variable functions
+            case 'type':
+                $value = @gettype($source);
+                break;
+            case 'not':
+                $value = @!$source;
+                break;
+            case 'empty':
+                $value = @empty($source);
+                break;
+            case 'isset':
+                $value = @isset($source);
+                break;
+            case 'isarray':
+                $value = @is_array($source);
+                break;
+            case 'isbool':
+                $value = @is_bool($source);
+                break;
+            case 'isfloat':
+            case 'isdouble':
+            case 'isreal':
+                $value = @is_float($source);
+                break;
+            case 'isint':
+            case 'isinteger':
+            case 'islong':
+                $value = @is_int($source);
+                break;
+            case 'isnull':
+                $value = @is_null($source);
+                break;
+            case 'isnotnull':
+                $value = @!is_null($source);
+                break;
+            case 'isnumeric':
+                $value = @is_numeric($source);
+                break;
+            case 'isobject':
+                $value = @is_object($source);
+                break;
+            case 'isscalar':
+                $value = @is_scalar($source);
+                break;
+            case 'isstring':
+                $value = @is_string($source);
+                break;
+            case 'int':
+                $value = @intval($source);
+                break;
+            case 'float':
+                $value = @floatval($source);
+                break;
+            case 'string':
+                $value = @strval($source);
+                break;
+            case 'bool':
+                $value = @(bool) $source;
+                break;
+            case 'array':
+                if (!is_array($source)) {
+                    if (is_null($source)) {
+                        $value = [];
+                    } else {
+                        $value = [$source];
+                    }
+                } else {
+                    $value = $source;
+                }
+                break;
+            case 'attr':
+                if (isset($source->{$params[0]})) {
+                    $value = @$source->{$params[0]};
+                }
+                break;
+            case 'in':
+                $value = false;
+                $i = 0;
+                while (isset($params[$i])) {
+                    $value = $value || $source == $params[$i];
+                    $i++;
+                }
+                break;
+            case 'between':
+                if (isset($params[2]) && $params[2]) {
+                    $value = ($source > $params[0] && $source < $params[1]);
+                } else {
+                    $value = ($source >= $params[0] && $source <= $params[1]);
+                }
+                break;
+            case 'ifeq':
+                $value = ($source == $params[0]);
+                break;
+            case 'ifne':
+                $value = ($source != $params[0]);
+                break;
+            case 'ifgt':
+                $value = ($source > $params[0]);
+                break;
+            case 'ifgte':
+                $value = ($source >= $params[0]);
+                break;
+            case 'iflt':
+                $value = ($source < $params[0]);
+                break;
+            case 'iflte':
+                $value = ($source <= $params[0]);
+                break;
+            case 'contains':
+                $value = (strpos($source, $params[0]) !== false);
+                break;
+            case 'starts-with':
+                $value = (strpos($source, $params[0]) === 0);
+                break;
+            case 'ends-with':
+                $value = (strrpos($source, $params[0]) === (strlen($source) - strlen($params[0]) + 1));
+                break;
+            case 'bit':
+                $value = ($source & (int) $params[0]) > 0;
+                break;
+
+            case 'then':
+                if ($source) {
+                    $value = $params[0];
+                } elseif (isset($params[1])) {
+                    $value = $params[1];
+                }
+                break;
+
+            case 'coalesce':
+                if (is_null($source)) {
+                    $value = $params[0];
+                } else {
+                    $value = $source;
+                }
+                break;
+
+            // String functions
+            case 'format':
+            case 'fmt':
+                $value = @sprintf($params[0], $source);
+                break;
+            case 'match':
+                $value = (bool) @preg_match($params[0], $source);
+                break;
+            case 'upper':
+                $value = @strtoupper($source);
+                break;
+            case 'lower':
+                $value = @strtolower($source);
+                break;
+            case 'ucfirst':
+                $value = @ucfirst($source);
+                break;
+            case 'lcfirst':
+                $value = @lcfirst($source);
+                break;
+            case 'ucwords':
+                $value = @ucwords($source);
+                break;
+            case 'split':
+            case 'explode':
+                $value = @explode($params[0], $source);
+                break;
+            case 'substr':
+                if (isset($params[1])) {
+                    $value = @substr($source, $params[0], $params[1]);
+                } else {
+                    $value = @substr($source, $params[0]);
+                }
+                break;
+            case 'join':
+            case 'implode':
+                $value = @implode($params[0], $source);
+                break;
+            case 'constant':
+                $value = @constant($source);
+                if (is_null($value) && $params[0]) {
+                    $value = $source;
+                }
+                break;
+            case 'print':
+                $value = @print_r($source, true);
+                break;
+            case 'json':
+                if (isset($params[0])) {
+                    $options = \JSON_PRETTY_PRINT;
+                } else {
+                    $options = 0;
+                }
+                $value = @json_encode($source, $options);
+                break;
+            case 'parse':
+                if (isset($params[0])) {
+                    $value = @json_decode($source, $params[0]);
+                } else {
+                    $value = @json_decode($source);
+                }
+                break;
+            case 'encodehtml':
+                $value = @htmlentities($source);
+                break;
+            case 'decodehtml':
+                $value = @html_entity_decode($source);
+                break;
+            case 'base64':
+                $value = @base64_encode($source);
+                break;
+            case 'cat':
+                $value = @implode($params);
+                break;
+            case 'dump':
+                ob_start();
+                var_dump($source);
+                $value = @ob_get_clean();
+                break;
+            case 'translate':
+                if (is_string($source) && $this->translator) {
+                    $catalog = null;
+                    if (isset($params[0])) {
+                        $catalog = $params[0];
+                    }
+                    $context = null;
+                    if (isset($params[1])) {
+                        $context = $params[1];
+                    }
+                    $value = $this->translator->getText($source, $context, $catalog);
+                } else {
+                    $value = $source;
+                }
+                break;
+
+            // Number functions
+            case 'add':
+                $value = @($source + $params[0]);
+                break;
+            case 'mul':
+                $value = @($source * $params[0]);
+                break;
+            case 'div':
+                $value = @($source / $params[0]);
+                break;
+            case 'mod':
+                $value = @($source % $params[0]);
+                break;
+        }
+
+        return $value;
+    }
+
+    protected function &getParamValue($param, $source=null)
+    {
+        if ($param[0] == "'" || $param[0] == '"') {
+            $value = substr($param, 1, -1);
+        } elseif (is_numeric($param)) {
+            $value = $param;
+        } else {
+            $instr = $this->parse($param);
+            $value = &$this->getData($instr, $source);
+        }
+        
+        return $value;
+    }
+
+    /* ------------------------------------------------------------------------
+        Merge instructions parser
+    ------------------------------------------------------------------------ */
+    protected function parse($instructionString, $sep=" ")
+    {
+        $args = $this->explode(trim($instructionString), $sep);
+
+        if (!count($args)) {
+            throw new \Exception("Invalid Template instruction : no main argument provided in $instructionString");
+        }
+
+        $parser = new \StdClass();
+        $parser->path = array_shift($args);
+        $parser->source = $this->getSource($parser->path);
+
+        $parser->params = array();
+
+        if (!count($args)) {
+            return $parser;
+        }
+
+        foreach ($args as $arg) {
+            if (preg_match('#^(?<name>\w+)\s*(=(["\'])(?<value>(?:[^\3\\\\]|\\\\.)*)\3)$#', $arg, $pair)) {
+                $parser->params[$pair['name']] = isset($pair['value']) ? $pair['value'] : null;
+            } elseif ($arg[0]=="@") {
+                $parser->params["attr"]  = substr($arg, 1);
+            } elseif ($arg[0]=="$") {
+                $parser->params["var"]  = substr($arg, 1);
+            } elseif ($arg[0]=="/") {
+                $parser->params["include"]  = substr($arg, 1);
+            } else {
+                $parser->params["source"]  = $arg;
+            }
+        }
+        
+        return $parser;
+    }
+
+    protected function getSource($data)
+    {
+        $source = array();
+        $steps = $this->tokenize($data);
+        for ($i=0, $l=count($steps); $i<$l; $i++) {
+            $step = $steps[$i];
+            switch(true) {
+                case $step == "" :
+                case $step == false :
+                    if ($i == 0) {
+                        $source[] = array('arg', '');
+                    } else {
+                        unset($step);
+                    }
+                    break;
+
+                //case $step[0] == ".":
+                //    $source[] = array('prop', substr($step, 1));
+                //    break;
+
+                case preg_match('#^\$(?<name>.*)$#', $step, $var):
+                    $source[] = array('var', $var['name']);
+                    break;
+
+                case preg_match('#^(?<ext>\w+):(?<name>.*)$#', $step, $ext):
+                    $source[] = array($ext['ext'], $ext['name']);
+                    break;
+
+                case preg_match('#^(?<name>[^(\/]+)\((?<params>.*)?\)$#', $step, $func) :
+                    $params = $this->explode($func['params'], ",");
+                    $source[] = array('func', $func['name'], $params);
+                    break;
+
+                case preg_match('#^\[(?<name>(?<enc>["\'])?[^\2]*\2?)\]$#', $step, $offset):
+                    $source[] = array('offset', $offset['name']);
+                    break;
+
+                case preg_match('#^\/(?<name>[^(]+)\((?<params>.*)?\)$#', $step, $method) :
+                    $params = $this->explode($method['params'], ",");
+                    $source[] = array('method', $method['name'], $params);
+                    break;
+
+                default:
+                    if ($i==0) {
+                        $source[] = array('source', $step);
+                    } else {
+                        $source[] = array('prop', $step);
+                    }
+            }
+        }
+        
+        return $source;
+    }
+
+    protected function explode($str, $sep)
+    {
+        $l = strlen($str);
+        $o = 0;
+        $esc = false;
+        $sq  = false;
+        $dq  = false;
+        $br  = 0;
+        $sbr = 0;
+        $tok = array();
+
+        for ($i=0; $i<$l; $i++) {
+            // Add token if separator found out of enclosures and brackets
+            if ($str[$i] == $sep && !$dq && !$sq && !$br && !$sbr) {
+                $tok[] = trim(substr($str, $o, $i-$o));
+                $o = $i+1;
+                continue;
+            }
+
+            // Ignore character if escaped
+            if ($esc) {
+                $esc = false;
+                continue;
+            }
+
+            // Special characters that affect parsing
+            switch($str[$i]) {
+            case "'":
+                if (!$sq) $sq = true;
+                else $sq = false;
+                break;
+            case '"':
+                if (!$dq) $dq = true;
+                else $dq = false;
+                break;
+            case '(':
+                if (!$sq && !$dq) $br++;
+                break;
+            case ')':
+                if (!$sq && !$dq) $br--;
+                break;
+            case '[':
+                if (!$sq && !$dq) $sbr++;
+                break;
+            case ']':
+                if (!$sq && !$dq) $sbr--;
+                break;
+            case '\\':
+                $esc = true;
+                break;
+            }
+        }
+        $tail = trim(substr($str, $o, $i-$o));
+        if ($tail !== "") {
+            $tok[] = $tail;
+        }
+
+        if ($sq || $dq || $br || $sbr || $esc) {
+            throw new \Exception("Invalid string: unexpected end of string at offset $i");
+        }
+
+        return $tok;
+    }
+
+    protected function tokenize($str)
+    {
+        $l = strlen($str);
+        $o = 0;
+        $esc = false;
+        $sq  = false;
+        $dq  = false;
+        $br  = 0;
+        $sbr = false;
+        $steps = array();
+        $step = false;
+
+        // Function
+        for ($i=0; $i<$l; $i++) {
+            // Tokenize only of out of enclosures
+            if (!$dq && !$sq && !$br) {
+                // Add token if dot found
+                if ($str[$i] == ".") {
+                    $steps[] = trim(substr($str, $o, $i-$o));
+                    $o = $i+1;
+                    continue;
+                }
+
+                // Add token if opening square bracket
+                if ($str[$i] == "[") {
+                    $steps[] = trim(substr($str, $o, $i-$o));
+                    $o = $i+1;
+                    $sbr = true;
+                    continue;
+                }
+
+                // Add token enclosed by square brackets
+                if ($str[$i] == "]" && $sbr) {
+                    $steps[] = trim(substr($str, $o-1, $i-$o+2));
+                    $o = $i+1;
+                    $sbr = false;
+                    continue;
+                }
+            }
+
+            // Ignore character if escaped
+            if ($esc) {
+                $esc = false;
+                continue;
+            }
+
+            // Special characters that affect parsing
+            switch($str[$i]) {
+            case "'":
+                if (!$sq) $sq = true;
+                else $sq = false;
+                break;
+            case '"':
+                if (!$dq) $dq = true;
+                else $dq = false;
+                break;
+            case '(':
+                if (!$sq && !$dq) $br++;
+                break;
+            case ')':
+                if (!$sq && !$dq) $br--;
+                break;
+            case '\\':
+                $esc = true;
+                break;
+            }
+        }
+        $tail = trim(substr($str, $o, $i-$o));
+        if ($tail !== false)
+            $steps[] = $tail;
+
+        if ($sq || $dq || $br || $sbr || $esc)
+            throw new \Exception("Invalid string: unexpected end of string at offset $i");
+
+        return $steps;
+    }
+}
\ No newline at end of file
diff --git a/modules/export_seda/example.php b/modules/export_seda/example.php
new file mode 100644
index 0000000000000000000000000000000000000000..e68205457d517c91fb4bc52cfb398d7b9125b850
--- /dev/null
+++ b/modules/export_seda/example.php
@@ -0,0 +1,2 @@
+require_once __DIR__.'/DOMTemplateProcessor.php';
+$DOMTemplate = new DOMDocument();$DOMTemplate->load(__DIR__.'/test.xml');$DOMTemplateProcessor = new DOMTemplateProcessor($DOMTemplate);$DOMTemplateProcessor->setSource('bar', 'bazbull');$DOMTemplateProcessor->merge();$xml = $DOMTemplate->saveXML();
\ No newline at end of file
diff --git a/modules/export_seda/export.php b/modules/export_seda/export.php
new file mode 100644
index 0000000000000000000000000000000000000000..ee9569f71e1bc2e52c30ef43904f3983f7690628
--- /dev/null
+++ b/modules/export_seda/export.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+*   Copyright 2008-2017 Maarch
+*
+*   This file is part of Maarch Framework.
+*
+*   Maarch Framework is free software: you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation, either version 3 of the License, or
+*   (at your option) any later version.
+*
+*   Maarch Framework is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*   along with Maarch Framework.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+require_once __DIR__.'/ArchiveTransferReply.php';
+require_once __DIR__.'/ArchiveTransfer.php';
+require_once __DIR__.'/Acknowledgement.php';
+// Args
+//ARCHIVE TRANSFER
+
+//$listResId = ['100','101','102'];
+
+//$archiveTransfer = new ArchiveTransfer();
+//$message = $archiveTransfer->receive($listResId);
+//$archiveTransfer->sendXml($message);
+
+
+// ACKNOWLEDGEMENT
+//$acknowledgement = new Acknowledgement();
+//$acknowledgement->send(__DIR__. DIRECTORY_SEPARATOR ."seda2". DIRECTORY_SEPARATOR . $message->messageIdentifier->value .".xml");
+
+//ARCHIVE TRANSFER REPLY
+/*
+$archiveTransferReply = new ArchiveTransfertReply();
+$archiveTransferReply->receive(__DIR__. DIRECTORY_SEPARATOR ."seda2". DIRECTORY_SEPARATOR . "bblier-20170216-163047_reply.xml");
+*/
\ No newline at end of file
diff --git a/modules/export_seda/export_seda.php b/modules/export_seda/export_seda.php
new file mode 100644
index 0000000000000000000000000000000000000000..18a53aed3a784ba84fdffe0c971cf37721539c6f
--- /dev/null
+++ b/modules/export_seda/export_seda.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+* Copyright Maarch since 2008 under licence GPLv3.
+* See LICENCE.txt file at the root folder for more details.
+* This file is part of Maarch software.
+*
+*/
+
+/**
+* @brief Export seda Action
+* @author dev@maarch.org
+* @ingroup export_seda
+*/
+
+
+/**
+* $confirm  bool true
+*/
+$confirm = true;
+
+/**
+* $etapes  array Contains only one etap, the status modification
+*/
+ 
+$etapes = array('export');
+
+
+function manage_export($arr_id, $history, $id_action, $label_action, $status)
+{
+    // récupérer l'entité racine du courrier
+    // récupérer transferring_agency et archival_agreement
+
+    // récupérer la duration et retention_rule du type de doc du courrier
+
+    // appel fonction de transfert et génération bdx
+
+    // historisation du transfert
+
+    // modification statut -> fait automatiquement par mécanique bannette
+
+    // ensuite il y a aura une suppression logique des documents et des contacts (si plus de courriers associés)
+
+    for($i=0; $i<count($arr_id);$i++)
+    {
+        $result .= $arr_id[$i].'#';
+        //$db->query("UPDATE ".$ext_table. " SET closing_date = CURRENT_TIMESTAMP WHERE res_id = ?", array($arr_id[$i]));
+
+    }
+
+    return array('result' => $result, 'history_msg' => '');
+}
+
diff --git a/modules/export_seda/lang/en.php b/modules/export_seda/lang/en.php
new file mode 100644
index 0000000000000000000000000000000000000000..531c92903f00cfce0c03c2e2faa8587accf6fbd2
--- /dev/null
+++ b/modules/export_seda/lang/en.php
@@ -0,0 +1,11 @@
+<?php
+
+if (!defined("_EXPORT_SEDA_COMMENT"))
+    define("_EXPORT_SEDA_COMMENT", "SEDA export");
+
+if (!defined("_EXPORT_SEDA"))
+    define("_EXPORT_SEDA", "SEDA export");
+
+if (!defined("_EXPORT_SEDA_VIEW"))
+    define("_EXPORT_SEDA_VIEW", "See SEDA export");
+
diff --git a/modules/export_seda/lang/fr.php b/modules/export_seda/lang/fr.php
new file mode 100644
index 0000000000000000000000000000000000000000..94a64d96ef7142b1385f219873b08de2122c1635
--- /dev/null
+++ b/modules/export_seda/lang/fr.php
@@ -0,0 +1,14 @@
+<?php
+
+if (!defined("_EXPORT_SEDA_COMMENT"))
+    define("_EXPORT_SEDA_COMMENT", "Export SEDA");
+
+if (!defined("_EXPORT_SEDA"))
+    define("_EXPORT_SEDA", "Export SEDA");
+
+
+if (!defined("_EXPORT_SEDA_VIEW"))
+    define("_EXPORT_SEDA_VIEW", "Voir le bordereau SEDA");
+
+
+
diff --git a/modules/export_seda/resources/AbstractRule.xml b/modules/export_seda/resources/AbstractRule.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a19e1967955259432ac7fac60ac1de1983558913
--- /dev/null
+++ b/modules/export_seda/resources/AbstractRule.xml
@@ -0,0 +1,4 @@
+<?merge $abstractRule.rule ?><Rule><?merge .value ?></Rule>
+<?merge $abstractRule.startDate ?><StartDate><?merge . ?></StartDate>
+<PreventInheritance><?merge $abstractRule.preventInheritance ?></PreventInheritance>
+<RefNonRuleId><?merge $abstractRule.refNonRuleId ?></RefNonRuleId>
\ No newline at end of file
diff --git a/modules/export_seda/resources/Acknowledgement.xml b/modules/export_seda/resources/Acknowledgement.xml
new file mode 100644
index 0000000000000000000000000000000000000000..59940f07d8029d0d656693054295a9a9003a2788
--- /dev/null
+++ b/modules/export_seda/resources/Acknowledgement.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Acknowledgement xmlns="fr:gouv:culture:archivesdefrance:seda:v2.0">
+	<?merge Acknowledgement.comment ?><Comment><?merge .value ?></Comment>
+	<Date><?merge Acknowledgement.date ?></Date>
+	<MessagIdentifier><?merge Acknowledgement.messageIdentifier ?></MessagIdentifier>
+	<Signature><?merge Acknowledgement.signature ?></Signature>
+	<MessageReceivedIdentifier><?merge Acknowledgement.messageReceivedIdentifier ?></MessageReceivedIdentifier>
+	<Sender><?merge Acknowledgement.sender ?></Sender>
+	<Receiver><?merge Acknowledgement.receiver ?></Receiver>
+</Acknowledgement>
\ No newline at end of file
diff --git a/modules/export_seda/resources/Agent.xml b/modules/export_seda/resources/Agent.xml
new file mode 100644
index 0000000000000000000000000000000000000000..47a9a0f57d9b8da6bd7034f22acc7a1dfb038636
--- /dev/null
+++ b/modules/export_seda/resources/Agent.xml
@@ -0,0 +1,15 @@
+<?merge $agent.firstName.bool() ?><FirstName><?merge $agent.firstName ?></FirstName>
+<?merge $agent.birthName.bool() ?><BirthName><?merge $agent.birthName ?></BirthName>
+<?merge $agent.givenName.bool() ?><GivenName><?merge $agent.givenName ?></GivenName>
+<?merge $agent.gender.bool() ?><Gender><?merge $agent.gender ?></Gender>
+<?merge $agent.birthDate.bool() ?><BirthDate><?merge $agent.birthDate ?></BirthDate>
+<?merge $agent.birthPlace.bool() ?><BirthPlace><?merge $agent.birthPlace ?></BirthPlace>
+<?merge $agent.deathDate.bool() ?><DeathDate><?merge $agent.deathDate ?></DeathDate>
+<?merge $agent.deathPlace.bool() ?><DeathPlace><?merge $agent.deathPlace ?></DeathPlace>
+<?merge $agent.nationality.bool() ?><Nationality><?merge $agent.nationality ?></Nationality>
+<?merge $agent.function.bool() ?><Function><?merge $agent.function ?></Function>
+<?merge $agent.activity.bool() ?><Activity><?merge $agent.activity ?></Activity>
+<?merge $agent.position.bool() ?><Position><?merge $agent.position ?></Position>
+<?merge $agent.role.bool() ?><Role><?merge $agent.role ?></Role>
+<?merge $agent.corpname.bool() ?><CorpName><?merge $agent.corpname ?></CorpName>
+<?merge $agent.identifier.bool() ?><Identifier><?merge $agent.identifier ?></Identifier>
\ No newline at end of file
diff --git a/modules/export_seda/resources/ArchivalAgreement.xml b/modules/export_seda/resources/ArchivalAgreement.xml
new file mode 100644
index 0000000000000000000000000000000000000000..43a39c64562c804d86aa567a62353e2d6af483d8
--- /dev/null
+++ b/modules/export_seda/resources/ArchivalAgreement.xml
@@ -0,0 +1 @@
+<ArchivalAgreement schemeID="[?merge $archivalAgreement.schemeID ?]" schemeName="[?merge $archivalAgreement.schemeName ?]" schemeAgencyID="[?merge $archivalAgreement.schemeAgencyID ?]" schemeAgencyName="[?merge $archivalAgreement.schemeAgencyName ?]" schemeVersionID="[?merge $archivalAgreement.schemeVersionID ?]" schemeDataURI="[?merge $archivalAgreement.schemeDataURI ?]" schemeURI="[?merge $archivalAgreement.schemeURI ?]"><?merge $archivalAgreement.value ?></ArchivalAgreement>
\ No newline at end of file
diff --git a/modules/export_seda/resources/ArchiveTransfer.xml b/modules/export_seda/resources/ArchiveTransfer.xml
new file mode 100644
index 0000000000000000000000000000000000000000..64c4639aea6157fd9fc2a626761ffc93193c2d36
--- /dev/null
+++ b/modules/export_seda/resources/ArchiveTransfer.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<ArchiveTransfer xmlns="fr:gouv:culture:archivesdefrance:seda:v2.0">
+    <?merge ArchiveTransfer.comment ?><Comment><?merge .value ?></Comment>
+    <Date><?merge ArchiveTransfer.date ?></Date>
+    <?merge ArchiveTransfer.messageIdentifier $messageIdentifier ?><?xinclude /resources/MessageIdentifier.xml ?>
+    <?merge ArchiveTransfer.archivalAgreement $archivalAgreement ?><?xinclude /resources/ArchivalAgreement.xml ?>
+    <?xinclude /resources/CodeListVersions.xml ?>
+    <?merge ArchiveTransfer.dataObjectPackage $dataObjectPackage ?>
+    <?xinclude /resources/DataObjectPackage.xml ?>
+    <ArchivalAgency>
+        <?merge ArchiveTransfer.archivalAgency $organization ?>
+        <?xinclude /resources/Organization.xml ?>
+    </ArchivalAgency>
+    <TransferringAgency>
+        <?merge ArchiveTransfer.transferringAgency $organization ?>
+        <?xinclude /resources/Organization.xml ?>
+    </TransferringAgency>
+</ArchiveTransfer>
\ No newline at end of file
diff --git a/modules/export_seda/resources/ArchiveUnit.xml b/modules/export_seda/resources/ArchiveUnit.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d5869fdc4301a17df2429eb2baec247741adab3f
--- /dev/null
+++ b/modules/export_seda/resources/ArchiveUnit.xml
@@ -0,0 +1,127 @@
+<?merge $archiveUnit ?>
+<ArchiveUnit>
+    <ArchiveUnitRefId><?merge .archiveUnitRefId ?></ArchiveUnitRefId>
+    <ArchiveUnitProfile schemeID="[?merge .archiveUnitProfile.schemeID ?]" schemeName="[?merge .archiveUnitProfile.schemeName ?]" schemeAgencyID="[?merge .archiveUnitProfile.schemeAgencyID ?]" schemeAgencyName="[?merge .archiveUnitProfile.schemeAgencyName ?]" schemeVersionID="[?merge .archiveUnitProfile.schemeVersionID ?]" schemeDataURI="[?merge .archiveUnitProfile.schemeDataURI ?]" schemeURI="[?merge .archiveUnitProfile.schemeURI ?]"><?merge .archiveUnitProfile ?></ArchiveUnitProfile>
+    <?merge .management.bool() ?>
+    <Management>
+        <StorageRule>
+            <?merge .management.storageRule $abstractRule ?>
+            <?xinclude /resources/AbstractRule.xml ?>
+            <FinalAction><?merge .management.storageRule.finalAction ?></FinalAction>
+        </StorageRule>
+        <AppraisalRule>
+            <?merge .management.appraisalRule $abstractRule ?>
+            <?xinclude /resources/AbstractRule.xml ?>
+            <FinalAction><?merge .management.appraisalRule.finalAction ?></FinalAction>
+        </AppraisalRule>
+        <AccessRule>
+            <?merge .management.accessRule $abstractRule ?>
+            <?xinclude /resources/AbstractRule.xml ?>
+        </AccessRule>
+        <DisseminationRule>
+            <?merge .management.disseminationRule $abstractRule ?>
+            <?xinclude /resources/AbstractRule.xml ?>
+        </DisseminationRule>
+        <ReuseRule>
+            <?merge .management.reuseRule $abstractRule ?>
+            <?xinclude /resources/AbstractRule.xml ?>
+        </ReuseRule>
+        <ClassificationRule>
+            <?merge .management.classificationRule $abstractRule ?>
+            <?xinclude /resources/AbstractRule.xml ?>
+            <ClassificationLevel><?merge .management.classificationRule.classificationLevel ?></ClassificationLevel>
+            <ClassificationOwner><?merge .management.classificationRule.classificationOwner ?></ClassificationOwner>
+            <ClassificationReassessingDate><?merge .management.classificationRule.classificationReassessingDate ?></ClassificationReassessingDate>
+            <NeedReassessingAuthorization><?merge .management.classificationRule.needReassessingAuthorization ?></NeedReassessingAuthorization>
+        </ClassificationRule>
+        <NeedAuthorization>
+            <?merge .management.needAuthorization ?>
+        </NeedAuthorization>
+        <OtherManagementAbstract>
+            <?merge .management.otherManagementAbstract ?>
+        </OtherManagementAbstract>
+    </Management>
+    <?merge .content.bool() ?>
+    <Content>
+        <DescriptionLevel listVersionID="[?merge .descriptionLevel ?]"><?merge .content.descriptionLevel ?></DescriptionLevel>
+        <?merge .content.title ?><Title><?merge . ?></Title>
+        <?merge .content.filePlanPosition ?><FilePlanPosition schemeID="[?merge .schemeID @schemeID ?]" schemeName="[?merge .schemeName @schemeName ?]" schemeAgencyID="[?merge .schemeAgencyID @schemeAgencyID ?]" schemeAgencyName="[?merge .schemeAgencyName @schemeAgencyName ?]" schemeVersionID="[?merge .schemeVersionID @schemeVersionID ?]" schemeDataURI="[?merge .schemeDataURI @schemeDataURI ?]" schemeURI="[?merge .schemeURI @schemeURI ?]"><?merge .value ?></FilePlanPosition>
+        <OriginatingAgencyArchiveIdentifier><?merge .content.originatingAgencyArchiveIdentifier ?></OriginatingAgencyArchiveIdentifier>
+        <?merge .content.description.bool() ?><Description><?merge .content.description ?></Description>
+        <?merge .content.custodialHistory.bool() ?><CustodialHistory>
+            <?merge .content.custodialHistory.custodialHistoryItem ?>
+            <CustodialHistoryItem when="[?merge .when ?]"><?merge .value ?></CustodialHistoryItem>
+        </CustodialHistory>
+        <Type><?merge .content.type ?></Type>
+        <DocumentType><?merge .content.documentType ?></DocumentType>
+        <Language><?merge .content.language ?></Language>
+        <DescriptionLanguage><?merge .content.descriptionLanguage ?></DescriptionLanguage>
+        <Status><?merge .content.status ?></Status>
+        <Version><?merge .content.version ?></Version>
+        <?merge .content.tag ?><Tag><?merge .value ?></Tag>
+        <?merge .content.keyword ?><Keyword>
+            <KeywordContent role="[?merge .keywordContent.role @role ?]"><?merge .keywordContent.value ?></KeywordContent>
+            <KeywordReference schemeID="[?merge .keywordReference.schemeID @schemeID ?]" schemeName="[?merge .keywordReference.schemeName @schemeName ?]" schemeAgencyID="[?merge .keywordReference.schemeAgencyID @schemeAgencyID ?]" schemeAgencyName="[?merge .keywordReference.schemeAgencyName @schemeAgencyName ?]" schemeVersionID="[?merge .keywordReference.schemeVersionID @schemeVersionID ?]" schemeDataURI="[?merge .keywordReference.schemeDataURI @schemeDataURI ?]" schemeURI="[?merge .keywordReference.schemeURI @schemeURI ?]"><?merge .keywordReference.value ?></KeywordReference>
+            <KeywordType listVersionID="[?merge .keywordType.listVersionID @listVersionID ?]"><?merge .keywordType ?></KeywordType>
+        </Keyword>
+        <Coverage>
+            <SpatialCoverage><?merge .content.spatialCoverage ?></SpatialCoverage>
+            <TemporalCoverage><?merge .content.temporalCoverage ?></TemporalCoverage>
+            <JuridicationalCoverage><?merge .content.juridictionalCoverage ?></JuridicationalCoverage>
+        </Coverage>
+        <?merge .content.originatingAgency.bool() ?>
+        <OriginatingAgency>
+            <?merge .content.originatingAgency $organization ?>
+            <?xinclude /resources/Organization.xml ?>
+        </OriginatingAgency>
+        <?merge .content.submissionAgency.bool() ?>
+        <SubmissionAgency>
+            <?merge .content.submissionAgency $organization ?>
+            <?xinclude /resources/Organization.xml ?>
+        </SubmissionAgency>
+        <?merge .content.authorizedAgend.bool() ?>
+        <AuthorizedAgent>
+            <?merge .authorizedAgent $agent ?>
+            <?xinclude /resources/Agent.xml ?>
+        </AuthorizedAgent>
+        <?merge .content.writter.array() ?>
+        <Writter>
+            <?merge . $agent ?>
+            <?xinclude /resources/Agent.xml ?>
+        </Writter>
+        <?merge .content.addressee.array()?>
+        <Addressee>
+            <?merge . $agent ?>
+            <?xinclude /resources/Agent.xml ?>
+        </Addressee>
+        <?merge .content.recipient.array() ?>
+        <Recipient>
+            <?merge . $agent ?>
+            <?xinclude /resources/Agent.xml ?>
+        </Recipient>
+        <Source><?merge .content.source ?></Source>
+        <CreatedDate><?merge .content.createdDate ?></CreatedDate>
+        <TransactedDate><?merge .content.transactedDate ?></TransactedDate>
+        <AcquiredDate><?merge .content.acquiredDate ?></AcquiredDate>
+        <SentDate><?merge .content.sentDate ?></SentDate>
+        <ReceivedDate><?merge .content.receivedDate ?></ReceivedDate>
+        <RegisteredDate><?merge .content.registeredDate ?></RegisteredDate>
+        <StartDate><?merge .content.startDate ?></StartDate>
+        <EndDate><?merge .content.endDate ?></EndDate>
+        <?merge .content.event ?>
+        <Event>
+            <EventIdentifier><?merge .eventIdentifier ?></EventIdentifier>
+            <EventType><?merge .eventType ?></EventType>
+            <EventDateTime><?merge .eventDateTime ?></EventDateTime>
+            <EventDetail><?merge .eventDetail ?></EventDetail>
+        </Event> 
+    </Content>
+    <?merge .content.archiveUnit /resources/ArchiveUnit.xml?>
+    <?merge .dataObjectReference.bool() ?>
+    <DataObjectReference>
+        <?merge .dataObjectReference.dataObjectReferenceId.bool() ?>
+        <DataObjectReferenceId><?merge .dataObjectReference.dataObjectReferenceId ?></DataObjectReferenceId>
+        <?merge .dataObjectReference.dataObjectGroupReferenceId.bool() ?>
+        <DataObjectGroupReferenceId><?merge .dataObjectReference.dataObjectGroupReferenceId ?></DataObjectGroupReferenceId>
+    </DataObjectReference>
+</ArchiveUnit>
\ No newline at end of file
diff --git a/modules/export_seda/resources/CodeListVersions.xml b/modules/export_seda/resources/CodeListVersions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2b7fc560186c254388d6ee7d6095983948879732
--- /dev/null
+++ b/modules/export_seda/resources/CodeListVersions.xml
@@ -0,0 +1,18 @@
+<CodeListVersions>
+  <ReplyCodeListVersion > </ReplyCodeListVersion>
+  <MessageDigestAlgorithmCodeListVersion > </MessageDigestAlgorithmCodeListVersion>
+  <MimeTypeCodeListVersion > </MimeTypeCodeListVersion>
+  <EncodingCodeListVersion > </EncodingCodeListVersion>
+  <FileFormatCodeListVersion > </FileFormatCodeListVersion>
+  <CompressionAlgorithmCodeListVersion > </CompressionAlgorithmCodeListVersion>
+  <DataObjectVersionCodeListVersion > </DataObjectVersionCodeListVersion>
+  <StorageRuleCodeListVersion > </StorageRuleCodeListVersion>
+  <AppraisalRuleCodeListVersion > </AppraisalRuleCodeListVersion>
+  <AccessRuleCodeListVersion > </AccessRuleCodeListVersion>
+  <DisseminationRuleCodeListVersion > </DisseminationRuleCodeListVersion>
+  <ReuseRuleCodeListVersion > </ReuseRuleCodeListVersion>
+  <ClassificationRuleCodeListVersion > </ClassificationRuleCodeListVersion>
+  <AuthorizationReasonCodeListVersion ></AuthorizationReasonCodeListVersion>
+  <RelationshipCodeListVersion ></RelationshipCodeListVersion>
+  <OtherCodeListAbstract ></OtherCodeListAbstract>
+</CodeListVersions>
diff --git a/modules/export_seda/resources/DataObjectPackage.xml b/modules/export_seda/resources/DataObjectPackage.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1647fdf1914452ce3df5c7ad120cb854c9c94866
--- /dev/null
+++ b/modules/export_seda/resources/DataObjectPackage.xml
@@ -0,0 +1,28 @@
+<DataObjectPackage>
+    <?merge $dataObjectPackage.binaryDataObject ?>
+    <BinaryDataObject id="[?merge .id ?]">
+        <Attachment filename="[?merge .attachment.filename ?]"/>
+        <Uri><?merge .uri ?></Uri>
+        <MessageDigest algorithm="[?merge .messageDigest.algorithm ?]"><?merge .messageDigest.value ?></MessageDigest>
+        <Size><?merge .size.value ?></Size>
+        <FormatIdentification>
+            <MimeType><?merge .formatIdentification.mimeType ?></MimeType>
+            <FormatId><?merge .formatIdentification.formatId ?></FormatId>
+        </FormatIdentification>
+        <?merge .fileInfo.bool() ?>
+        <FileInfo>
+            <Filename><?merge .fileInfo.filename ?></Filename>
+        </FileInfo>
+    </BinaryDataObject>
+    <?merge $dataObjectPackage.physicalDataObject ?>
+    <PhysicalDataObject>
+        <?merge .bool() ?>
+        <PhysicalId schemeID="[?merge .physicalId.schemeID ?]" schemeName="[?merge .physicalId.schemeName ?]" schemeAgencyID="[?merge .physicalId.schemeAgencyID ?]" schemeAgencyName="[?merge .physicalId.schemeAgencyName ?]" schemeVersionID="[?merge .physicalId.schemeVersionID ?]" schemeDataURI="[?merge .physicalId.schemeDataURI ?]" schemeURI="[?merge .physicalId.schemeURI ?]"><?merge .physicalId.value ?></PhysicalId>
+    </PhysicalDataObject>
+    <DescriptiveMetadata>
+        <?merge $dataObjectPackage.descriptiveMetadata.archiveUnit $archiveUnit?>
+        <?xinclude /resources/ArchiveUnit.xml ?>
+    </DescriptiveMetadata>
+    <?merge $dataObjectPackage.managementMetadata $managementMetadata ?>
+    <?xinclude /resources/ManagementMetadata.xml ?>
+</DataObjectPackage>
\ No newline at end of file
diff --git a/modules/export_seda/resources/ManagementMetadata.xml b/modules/export_seda/resources/ManagementMetadata.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0fd3fc090426c84995263f0e176852048fae38ee
--- /dev/null
+++ b/modules/export_seda/resources/ManagementMetadata.xml
@@ -0,0 +1,48 @@
+<ManagementMetadata>
+    <?merge $managementMetadata.archivalProfile.bool() ?><ArchivalProfile><?merge $managementMetadata.archivalProfile.value ?></ArchivalProfile>
+    <?merge $managementMetadata.serviceLevel.bool() ?><ServiceLevel><?merge $managementMetadata.serviceLevel.value ?></ServiceLevel>
+    <?merge $managementMetadata.storageRule.bool() ?>
+    <StorageRule>
+        <?merge $managementMetadata.storageRule $abstractRule ?>
+        <?xinclude /resources/AbstractRule.xml ?>
+        <FinalAction><?merge $managementMetadata.storageRule.finalAction ?></FinalAction>
+    </StorageRule>
+    <?merge $managementMetadata.appraisalRule.bool() ?>
+    <AppraisalRule>
+        <?merge $managementMetadata.appraisalRule $abstractRule ?>
+        <?xinclude /resources/AbstractRule.xml ?>
+        <FinalAction><?merge $managementMetadata.appraisalRule.finalAction ?></FinalAction>
+    </AppraisalRule>
+    <?merge $managementMetadata.accessRule.bool() ?>
+    <AccessRule>
+        <?merge $managementMetadata.accessRule $abstractRule ?>
+        <?xinclude /resources/AbstractRule.xml ?>
+    </AccessRule>
+    <?merge $managementMetadata.disseminationRule.bool() ?>
+    <DisseminationRule>
+        <?merge $managementMetadata.disseminationRule $abstractRule ?>
+        <?xinclude /resources/AbstractRule.xml ?>
+    </DisseminationRule>
+    <?merge $managementMetadata.reuseRule.bool() ?>
+    <ReuseRule>
+        <?merge $managementMetadata.reuseRule $abstractRule ?>
+        <?xinclude /resources/AbstractRule.xml ?>
+    </ReuseRule>
+    <?merge $managementMetadata.classificationRule.bool() ?>
+    <ClassificationRule>
+        <?merge $managementMetadata.classificationRule $abstractRule ?>
+        <?xinclude /resources/AbstractRule.xml ?>
+        <ClassificationLevel><?merge $managementMetadata.classificationRule.classificationLevel ?></ClassificationLevel>
+        <ClassificationOwner><?merge $managementMetadata.classificationRule.classificationOwner ?></ClassificationOwner>
+        <ClassificationReassessingDate><?merge $managementMetadata.classificationRule.classificationReassessingDate ?></ClassificationReassessingDate>
+        <NeedReassessingAuthorization><?merge $managementMetadata.classificationRule.needReassessingAuthorization ?></NeedReassessingAuthorization>
+    </ClassificationRule>
+    <?merge $managementMetadata.needAuthorization.bool() ?>
+    <NeedAuthorization>
+        <?merge $managementMetadata.needAuthorization ?>
+    </NeedAuthorization>
+    <?merge $managementMetadata.otherManagementAbstract.bool() ?>
+    <OtherManagementAbstract>
+        <?merge $managementMetadata.otherManagementAbstract ?>
+    </OtherManagementAbstract>
+</ManagementMetadata>
\ No newline at end of file
diff --git a/modules/export_seda/resources/MessageIdentifier.xml b/modules/export_seda/resources/MessageIdentifier.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5dbb244cd712512b3a24d480b99e53e1e6bad481
--- /dev/null
+++ b/modules/export_seda/resources/MessageIdentifier.xml
@@ -0,0 +1 @@
+<MessageIdentifier schemeID="[?merge $messageIdentifier.schemeID ?]" schemeName="[?merge $messageIdentifier.schemeName ?]" schemeAgencyID="[?merge $messageIdentifier.schemeAgencyID ?]" schemeAgencyName="[?merge $messageIdentifier.schemeAgencyName ?]" schemeVersionID="[?merge $messageIdentifier.schemeVersionID ?]" schemeDataURI="[?merge $messageIdentifier.schemeDataURI ?]" schemeURI="[?merge $messageIdentifier.schemeURI ?]"><?merge $messageIdentifier.value ?></MessageIdentifier>
\ No newline at end of file
diff --git a/modules/export_seda/resources/Organization.xml b/modules/export_seda/resources/Organization.xml
new file mode 100644
index 0000000000000000000000000000000000000000..61967de7d4797f01c459e8122cbbf067ac67eb67
--- /dev/null
+++ b/modules/export_seda/resources/Organization.xml
@@ -0,0 +1,2 @@
+<Identifier schemeID="[?merge $organization.identifier.schemeID @schemeID ?]" schemeName="[?merge $organization.identifier.schemeName @schemeName ?]" schemeAgencyID="[?merge $organization.identifier.schemeAgencyID @schemeAgencyID ?]" schemeAgencyName="[?merge $organization.identifier.schemeAgencyName @schemeAgencyName ?]" schemeVersionID="[?merge $organization.identifier.schemeVersionID @schemeVersionID ?]" schemeDataURI="[?merge $organization.identifier.schemeDataURI @schemeDataURI ?]" schemeURI="[?merge $organization.identifier.schemeURI @schemeURI ?]"><?merge $organization.identifier.value ?></Identifier>
+<OrganizationDescriptiveMetadata></OrganizationDescriptiveMetadata>
\ No newline at end of file
diff --git a/modules/export_seda/sql/seda.pgsql.sql b/modules/export_seda/sql/seda.pgsql.sql
new file mode 100644
index 0000000000000000000000000000000000000000..9b4b8eddb8d4f32f6342f8ca959122c3f9279f66
--- /dev/null
+++ b/modules/export_seda/sql/seda.pgsql.sql
@@ -0,0 +1,50 @@
+DROP TABLE IF EXISTS seda;
+DROP TABLE IF EXISTS unit_identifier;
+
+CREATE TABLE seda
+(
+  "message_id" text NOT NULL,
+  "schema" text,
+  "type" text NOT NULL,
+  "status" text NOT NULL,
+  
+  "date" timestamp NOT NULL,
+  "reference" text NOT NULL,
+  
+  "account_id" text,
+  "sender_org_identifier" text NOT NULL,
+  "sender_org_name" text,
+  "recipient_org_identifier" text NOT NULL,
+  "recipient_org_name" text,
+
+  "archival_agreement_reference" text,
+  "reply_code" text,
+  "operation_date" timestamp,
+  "reception_date" timestamp,
+  
+  "related_reference" text,
+  "request_reference" text,
+  "reply_reference" text,
+  "derogation" boolean,
+  
+  "data_object_count" integer,
+  "size" numeric,
+  
+  "data" text,
+  
+  "active" boolean,
+  "archived" boolean,
+
+  PRIMARY KEY ("message_id")
+)
+WITH (
+  OIDS=FALSE
+);
+
+
+CREATE TABLE unit_identifier
+(
+  "message_id" text NOT NULL,
+  "tablename" text NOT NULL,
+  "res_id" text NOT NULL
+);
\ No newline at end of file
diff --git a/modules/export_seda/xml/IVS/data_types.xml b/modules/export_seda/xml/IVS/data_types.xml
new file mode 100644
index 0000000000000000000000000000000000000000..710b3b566515c85e605bd4166463e16613cbb609
--- /dev/null
+++ b/modules/export_seda/xml/IVS/data_types.xml
@@ -0,0 +1,3 @@
+<dataTypes>
+
+</dataTypes>
\ No newline at end of file
diff --git a/modules/export_seda/xml/IVS/requests_definitions.xml b/modules/export_seda/xml/IVS/requests_definitions.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d45cdc97cacfb004c4e920b0058fbd1d406ac3f2
--- /dev/null
+++ b/modules/export_seda/xml/IVS/requests_definitions.xml
@@ -0,0 +1,3 @@
+<requestDefinitions>
+
+</requestDefinitions>
\ No newline at end of file
diff --git a/modules/export_seda/xml/IVS/validation_rules.xml b/modules/export_seda/xml/IVS/validation_rules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..07950313a35e2a1052c593b81f32fed890c8347e
--- /dev/null
+++ b/modules/export_seda/xml/IVS/validation_rules.xml
@@ -0,0 +1,3 @@
+<validationRules>
+
+</validationRules>
\ No newline at end of file
diff --git a/modules/export_seda/xml/config.xml b/modules/export_seda/xml/config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0c34255604ecb7c26cc715cdfb41f8a30b5a09cd
--- /dev/null
+++ b/modules/export_seda/xml/config.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+    <CONFIG>
+        <name>export_seda</name>
+        <comment>_EXPORT_SEDA_COMMENT</comment>
+        <file_prefix>seda</file_prefix>
+        <loaded>true</loaded>
+    </CONFIG>
+    <TABLENAME/>
+    <HISTORY>
+        <sedaup>true</sedaup>
+        <sedaadd>true</sedaadd>
+        <sedadel>true</sedadel>
+    </HISTORY>
+</root>
diff --git a/modules/export_seda/xml/services.xml b/modules/export_seda/xml/services.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e93e9eed9fa2462dff1d320cc19a8dfdad5bf3d6
--- /dev/null
+++ b/modules/export_seda/xml/services.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<root>
+    <SERVICE>
+       <id>export_seda_view</id>
+       <name>_EXPORT_SEDA_VIEW</name>
+       <comment>_EXPORT_SEDA_DESC</comment>
+       <servicepage>export_seda_view.php</servicepage>
+       <servicetype>use</servicetype>
+       <system_service>false</system_service>
+       <enabled>true</enabled>
+       <WHEREAMIUSED>
+         <page>details.php</page>
+         <nature>include</nature>
+       </WHEREAMIUSED>
+    </SERVICE>
+</root>
diff --git a/sql/160_to_161.sql b/sql/160_to_161.sql
index 351c2bedecca337d1bf4f7e8bf97e1b7a99e35f5..0f4cf8cceeb5fc9879c604c2ef37277738b8a4a2 100644
--- a/sql/160_to_161.sql
+++ b/sql/160_to_161.sql
@@ -99,3 +99,68 @@ WITH (
 );
 
 
+
+DROP TABLE IF EXISTS seda;
+
+CREATE TABLE seda
+(
+  "message_id" text NOT NULL,
+  "schema" text,
+  "type" text NOT NULL,
+  "status" text NOT NULL,
+  
+  "date" timestamp NOT NULL,
+  "reference" text NOT NULL,
+  
+  "account_id" text,
+  "sender_org_identifier" text NOT NULL,
+  "sender_org_name" text,
+  "recipient_org_identifier" text NOT NULL,
+  "recipient_org_name" text,
+
+  "archival_agreement_reference" text,
+  "reply_code" text,
+  "operation_date" timestamp,
+  "reception_date" timestamp,
+  
+  "related_reference" text,
+  "request_reference" text,
+  "reply_reference" text,
+  "derogation" boolean,
+  
+  "data_object_count" integer,
+  "size" numeric,
+  
+  "data" text,
+  
+  "active" boolean,
+  "archived" boolean,
+
+  PRIMARY KEY ("message_id")
+)
+WITH (
+  OIDS=FALSE
+);
+
+DROP TABLE IF EXISTS unit_identifier;
+
+CREATE TABLE unit_identifier
+(
+  "message_id" text NOT NULL,
+  "tablename" text NOT NULL,
+  "res_id" text NOT NULL
+);
+
+
+ALTER TABLE doctypes DROP COLUMN IF EXISTS retention_rule;
+ALTER TABLE doctypes ADD COLUMN retention_rule character varying(255) NOT NULL DEFAULT 'destruction';
+
+ALTER TABLE doctypes DROP COLUMN IF EXISTS duration;
+ALTER TABLE doctypes ADD COLUMN duration character varying(15) NOT NULL DEFAULT 'P10Y';
+
+
+ALTER TABLE entities DROP COLUMN IF EXISTS transferring_agency;
+ALTER TABLE entities ADD COLUMN transferring_agency character varying(255);
+
+ALTER TABLE entities DROP COLUMN IF EXISTS archival_agreement;
+ALTER TABLE entities ADD COLUMN archival_agreement character varying(255);
diff --git a/sql/structure.sql b/sql/structure.sql
index 2e3398510d19dabb07ebbda47e6635d1c706a8aa..6b50947cbdb0298dc5bc665103aca237348aff59 100644
--- a/sql/structure.sql
+++ b/sql/structure.sql
@@ -111,6 +111,8 @@ CREATE TABLE doctypes
   doctypes_second_level_id integer,
   primary_retention  character varying(50) DEFAULT NULL,
   secondary_retention  character varying(50) DEFAULT NULL,
+  retention_rule character varying(255) NOT NULL DEFAULT 'destruction'::character varying,
+  duration character varying(15) NOT NULL DEFAULT 'P10Y'::character varying,
   CONSTRAINT doctypes_pkey PRIMARY KEY (type_id)
 )
 WITH (OIDS=FALSE);
@@ -824,6 +826,8 @@ CREATE TABLE entities
   entity_type character varying(64),
   entity_path character varying(2048),
   ldap_id character varying(255),
+  transferring_agency character varying(255),
+  archival_agreement character varying(255),
   CONSTRAINT entities_pkey PRIMARY KEY (entity_id)
 )
 WITH (OIDS=FALSE);
@@ -4098,3 +4102,51 @@ CREATE FUNCTION order_alphanum(text) RETURNS text AS $$
         E'(^|\\D)(\\d{7}($|\\D))', E'\\100\\2', 'g'),
           E'(^|\\D)(\\d{8}($|\\D))', E'\\10\\2', 'g');
 $$ LANGUAGE SQL;
+
+
+CREATE TABLE seda
+(
+  "message_id" text NOT NULL,
+  "schema" text,
+  "type" text NOT NULL,
+  "status" text NOT NULL,
+  
+  "date" timestamp NOT NULL,
+  "reference" text NOT NULL,
+  
+  "account_id" text,
+  "sender_org_identifier" text NOT NULL,
+  "sender_org_name" text,
+  "recipient_org_identifier" text NOT NULL,
+  "recipient_org_name" text,
+
+  "archival_agreement_reference" text,
+  "reply_code" text,
+  "operation_date" timestamp,
+  "reception_date" timestamp,
+  
+  "related_reference" text,
+  "request_reference" text,
+  "reply_reference" text,
+  "derogation" boolean,
+  
+  "data_object_count" integer,
+  "size" numeric,
+  
+  "data" text,
+  
+  "active" boolean,
+  "archived" boolean,
+
+  PRIMARY KEY ("message_id")
+)
+WITH (
+  OIDS=FALSE
+);
+
+CREATE TABLE unit_identifier
+(
+  "message_id" text NOT NULL,
+  "tablename" text NOT NULL,
+  "res_id" text NOT NULL
+);
\ No newline at end of file