diff --git a/src/main/java/org/olat/core/util/PathUtils.java b/src/main/java/org/olat/core/util/PathUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..c49169774e39594770724a615e383e89e87555ba
--- /dev/null
+++ b/src/main/java/org/olat/core/util/PathUtils.java
@@ -0,0 +1,105 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+
+/**
+ * 
+ * Initial date: 08.05.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class PathUtils {
+	
+	public static Path visit(File file, String filename, FileVisitor<Path> visitor) 
+	throws IOException {
+		if(!StringHelper.containsNonWhitespace(filename)) {
+			filename = file.getName();
+		}
+		
+		Path fPath = null;
+		if(file.isDirectory()) {
+			fPath = file.toPath();
+		} else if(filename != null && filename.toLowerCase().endsWith(".zip")) {
+			fPath = FileSystems.newFileSystem(file.toPath(), null).getPath("/");
+		} else {
+			fPath = file.toPath();
+		}
+		if(fPath != null) {
+		    Files.walkFileTree(fPath, visitor);
+		}
+		return fPath;
+	}
+	
+	public static class YesMatcher implements PathMatcher {
+		@Override
+		public boolean matches(Path path) {
+			return true;
+		}
+	}
+	
+	public static class CopyVisitor extends SimpleFileVisitor<Path> {
+
+		private final Path source;
+		private final Path destDir;
+		private final PathMatcher filter;
+		
+		public CopyVisitor(Path source, Path destDir, PathMatcher filter) {
+			this.source = source;
+			this.destDir = destDir;
+			this.filter = filter;
+		}
+		
+		@Override
+		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+	    throws IOException {
+			Path relativeFile = source.relativize(file);
+	        final Path destFile = Paths.get(destDir.toString(), relativeFile.toString());
+	        if(filter.matches(file)) {
+	        	Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
+	        }
+	        return FileVisitResult.CONTINUE;
+		}
+	 
+		@Override
+		public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+		throws IOException {
+			Path relativeDir = source.relativize(dir);
+	        final Path dirToCreate = Paths.get(destDir.toString(), relativeDir.toString());
+	        if(Files.notExists(dirToCreate)){
+	        	Files.createDirectory(dirToCreate);
+	        }
+	        return FileVisitResult.CONTINUE;
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
index edf45415ba590f4e81b5c04a7d92fdf191fc0ad4..68e013cf7bfacffccf140875191999185440cb45 100644
--- a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
+++ b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
@@ -36,6 +36,7 @@ import org.dom4j.Attribute;
 import org.dom4j.CDATA;
 import org.dom4j.Document;
 import org.dom4j.DocumentFactory;
+import org.dom4j.DocumentHelper;
 import org.dom4j.Element;
 import org.dom4j.Node;
 import org.dom4j.io.OutputFormat;
@@ -83,10 +84,26 @@ public class QTIExportProcessor {
 		String rootDir = "qitem_" + fullItem.getKey();
 		List<VFSItem> items = container.getItems();
 		for(VFSItem item:items) {
+			addMetadata(fullItem, rootDir, zout);
 			ZipUtil.addToZip(item, rootDir, zout);
 		}
 	}
 	
+	private void addMetadata(QuestionItemFull fullItem, String dir, ZipOutputStream zout) {
+		try {
+			Document document = DocumentHelper.createDocument();
+			Element qtimetadata = document.addElement("qtimetadata");
+			QTIMetadata enricher = new QTIMetadata(qtimetadata);
+			enricher.toXml(fullItem);
+			zout.putNextEntry(new ZipEntry(dir + "/" + "qitem_" + fullItem.getKey() + "_metadata.xml"));
+			OutputFormat format = OutputFormat.createPrettyPrint();
+			XMLWriter writer = new XMLWriter(zout, format);
+			writer.write(document);
+		} catch (IOException e) {
+			log.error("",  e);
+		}
+	}
+	
 	/**
 	 * <li>List all items
 	 * <li>Rewrite path
@@ -294,7 +311,7 @@ public class QTIExportProcessor {
 		//metadata
 		/*
 		<qtimetadata>
-      <qtimetadatafield>
+      	<qtimetadatafield>
         <fieldlabel>qmd_assessmenttype</fieldlabel>
         <fieldentry>Assessment</fieldentry>
       </qtimetadatafield>
@@ -320,6 +337,14 @@ public class QTIExportProcessor {
 		return section;
 	}
 	
+	private void addMetadataField(String label, String entry, Element qtimetadata) {
+		if(entry != null) {
+			Element qtimetadatafield = qtimetadata.addElement("qtimetadatafield");
+			qtimetadatafield.addElement("fieldlabel").setText(label);
+			qtimetadatafield.addElement("fieldentry").setText(entry);
+		}
+	}
+	
 	private Element readItemXml(VFSLeaf leaf) {
 		Document doc = null;
 		try {
@@ -379,100 +404,10 @@ public class QTIExportProcessor {
 	
 	private void enrichWithMetadata(QuestionItemFull fullItem, Element item) {
 		Element qtimetadata = (Element)item.selectSingleNode("./itemmetadata/qtimetadata");
-		String path = fullItem.getTaxonomicPath();
+		QTIMetadata enricher = new QTIMetadata(qtimetadata);
+		enricher.toXml(fullItem);
 	}
 	
-	private void addMetadataField(String label, String entry, Element qtimetadata) {
-		Element qtimetadatafield = qtimetadata.addElement("qtimetadatafield");
-		qtimetadatafield.addElement("fieldlabel").setText(label);
-		qtimetadatafield.addElement("fieldentry").setText(entry);
-	}
-	
-	/*
-	 * 
-	 * <itemmetadata>
-					<qtimetadata>
-						<qtimetadatafield>
-							<fieldlabel>qmd_levelofdifficulty</fieldlabel>
-							<fieldentry>basic</fieldentry>
-						</qtimetadatafield>
-						<qtimetadatafield>
-							<fieldlabel>qmd_topic</fieldlabel>
-							<fieldentry>qtiv1p2test</fieldentry>
-						</qtimetadatafield>
-					</qtimetadata>
-				</itemmetadata>
-
-				<qtimetadata>
-            <vocabulary uri="imsqtiv1p2_metadata.txt" vocab_type="text/plain"/>
-            <qtimetadatafield>
-               <fieldlabel>qmd_weighting</fieldlabel>
-               <fieldentry>2</fieldentry>
-            </qtimetadatafield>
-            ...
-         </qtimetadata>
-
-         
-         
-         http://qtimigration.googlecode.com/svn-history/r29/trunk/pyslet/unittests/data_imsqtiv1p2p1/input/
-
-
-<qtimetadatafield>
-                    <fieldlabel>name</fieldlabel>
-                    <fieldentry>Metadata New-Style</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>marks</fieldlabel>
-                    <fieldentry>50.0</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>syllabusarea</fieldlabel>
-                    <fieldentry>Migration</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>author</fieldlabel>
-                    <fieldentry>Steve Author</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>creator</fieldlabel>
-                    <fieldentry>Steve Creator</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>owner</fieldlabel>
-                    <fieldentry>Steve Owner</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>item type</fieldlabel>
-                    <fieldentry>MCQ</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>status</fieldlabel>
-                    <fieldentry>Experimental</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>qmd_levelofdifficulty</fieldlabel>
-                    <fieldentry>Professional Development</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>qmd_toolvendor</fieldlabel>
-                    <fieldentry>Steve Lay</fieldentry>
-                </qtimetadatafield>
-                <qtimetadatafield>
-                    <fieldlabel>description</fieldlabel>
-                    <fieldentry>General Description Extension</fieldentry>
-                </qtimetadatafield>
-                
-                
-                <itemmetadata>
-            <qmd_itemtype>MCQ</qmd_itemtype>
-            <qmd_levelofdifficulty>Professional Development</qmd_levelofdifficulty>
-            <qmd_maximumscore>50.0</qmd_maximumscore>
-            <qmd_status>Experimental</qmd_status>
-            <qmd_toolvendor>Steve Lay</qmd_toolvendor>
-            <qmd_topic>Migration</qmd_topic>
-        </itemmetadata>
-	 */
-	
 	private static final class HTMLHandler extends DefaultHandler {
 		private final List<String> materialPath = new ArrayList<String>();
 		
diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java
index 57e9250aeaeac7a767a16c891d827134eaaac246..ecdd8967f01c998d36d5514f1bb7bddaa2070da2 100644
--- a/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java
+++ b/src/main/java/org/olat/ims/qti/qpool/QTIImportProcessor.java
@@ -27,7 +27,14 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.StringReader;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.zip.ZipEntry;
@@ -40,13 +47,18 @@ import org.dom4j.Document;
 import org.dom4j.DocumentFactory;
 import org.dom4j.Element;
 import org.dom4j.io.OutputFormat;
+import org.dom4j.io.SAXReader;
 import org.dom4j.io.XMLWriter;
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
+import org.olat.core.util.PathUtils.CopyVisitor;
+import org.olat.core.util.PathUtils.YesMatcher;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.ZipUtil;
+import org.olat.core.util.vfs.LocalImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.xml.XMLParser;
@@ -56,10 +68,11 @@ import org.olat.ims.qti.editor.beecom.parser.ItemParser;
 import org.olat.ims.resources.IMSEntityResolver;
 import org.olat.modules.qpool.QuestionItem;
 import org.olat.modules.qpool.QuestionType;
-import org.olat.modules.qpool.manager.QPoolFileStorage;
 import org.olat.modules.qpool.manager.QEducationalContextDAO;
 import org.olat.modules.qpool.manager.QItemTypeDAO;
+import org.olat.modules.qpool.manager.QPoolFileStorage;
 import org.olat.modules.qpool.manager.QuestionItemDAO;
+import org.olat.modules.qpool.manager.TaxonomyLevelDAO;
 import org.olat.modules.qpool.model.QEducationalContext;
 import org.olat.modules.qpool.model.QItemType;
 import org.olat.modules.qpool.model.QuestionItemImpl;
@@ -86,20 +99,25 @@ class QTIImportProcessor {
 	private final String importedFilename;
 	private final File importedFile;
 
+	private final DB dbInstance;
 	private final QItemTypeDAO qItemTypeDao;
 	private final QPoolFileStorage qpoolFileStorage;
 	private final QuestionItemDAO questionItemDao;
+	private final TaxonomyLevelDAO taxonomyLevelDao;
 	private final QEducationalContextDAO qEduContextDao;
 	
 	public QTIImportProcessor(Identity owner, Locale defaultLocale, QuestionItemDAO questionItemDao,
-			QItemTypeDAO qItemTypeDao, QEducationalContextDAO qEduContextDao, QPoolFileStorage qpoolFileStorage) {
-		this(owner, defaultLocale, null, null, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+			QItemTypeDAO qItemTypeDao, QEducationalContextDAO qEduContextDao,
+			TaxonomyLevelDAO taxonomyLevelDao, QPoolFileStorage qpoolFileStorage, DB dbInstance) {
+		this(owner, defaultLocale, null, null, questionItemDao, qItemTypeDao, qEduContextDao,
+				taxonomyLevelDao, qpoolFileStorage, dbInstance);
 	}
 
 	public QTIImportProcessor(Identity owner, Locale defaultLocale, String importedFilename, File importedFile,
 			QuestionItemDAO questionItemDao, QItemTypeDAO qItemTypeDao, QEducationalContextDAO qEduContextDao,
-			QPoolFileStorage qpoolFileStorage) {
+			TaxonomyLevelDAO taxonomyLevelDao, QPoolFileStorage qpoolFileStorage, DB dbInstance) {
 		this.owner = owner;
+		this.dbInstance = dbInstance;
 		this.defaultLocale = defaultLocale;
 		this.importedFilename = importedFilename;
 		this.importedFile = importedFile;
@@ -107,20 +125,18 @@ class QTIImportProcessor {
 		this.questionItemDao = questionItemDao;
 		this.qEduContextDao = qEduContextDao;
 		this.qpoolFileStorage = qpoolFileStorage;
+		this.taxonomyLevelDao = taxonomyLevelDao;
 	}
 	
 	public List<QuestionItem> process() {
 		List<QuestionItem> qItems = new ArrayList<QuestionItem>();
 		try {
-			DocInfos docInfos = getDocInfos();
-			if(docInfos != null && docInfos.doc != null) {
-				List<ItemInfos> itemInfos = getItemList(docInfos);
-				for(ItemInfos itemInfo:itemInfos) {
-					QuestionItemImpl qItem = processItem(docInfos, itemInfo);
-					if(qItem != null) {
-						processFiles(qItem, itemInfo);
-						qItems.add(qItem);
-					}
+			List<DocInfos> docInfoList = getDocInfos();
+			if(docInfoList != null) {
+				for(DocInfos docInfos:docInfoList) {
+					List<QuestionItem> processdItems = process(docInfos);
+					qItems.addAll(processdItems);
+					dbInstance.commit();
 				}
 			}
 		} catch (IOException e) {
@@ -128,6 +144,22 @@ class QTIImportProcessor {
 		}
 		return qItems;
 	}
+	
+	private List<QuestionItem> process(DocInfos docInfos) {
+		List<QuestionItem> qItems = new ArrayList<>();
+		if(docInfos.doc != null) {
+			List<ItemInfos> itemInfos = getItemList(docInfos);
+			for(ItemInfos itemInfo:itemInfos) {
+				QuestionItemImpl qItem = processItem(docInfos, itemInfo);
+				if(qItem != null) {
+					processFiles(qItem, itemInfo, docInfos);
+					qItem = questionItemDao.merge(qItem);
+					qItems.add(qItem);
+				}
+			}
+		}
+		return qItems;
+	}
 
 	protected List<ItemInfos> getItemList(DocInfos doc) {
 		Document document = doc.getDocument();
@@ -157,10 +189,11 @@ class QTIImportProcessor {
 		if(itemInfos.isOriginalItem()) {
 			originalFilename = docInfos.filename;
 		}
-		return processItem(itemEl, comment, originalFilename, null, null);
+		return processItem(itemEl, comment, originalFilename, null, null, docInfos);
 	}
 	
-	protected QuestionItemImpl processItem(Element itemEl, String comment, String originalItemFilename, String editor, String editorVersion) {
+	protected QuestionItemImpl processItem(Element itemEl, String comment, String originalItemFilename,
+			String editor, String editorVersion, DocInfos docInfos) {
 		//filename
 		String filename;
 		String ident = getAttributeValue(itemEl, "ident");
@@ -181,6 +214,7 @@ class QTIImportProcessor {
 		if(!StringHelper.containsNonWhitespace(title)) {
 			title = importedFilename;
 		}
+
 		QuestionItemImpl poolItem = questionItemDao.create(title, QTIConstants.QTI_12_FORMAT, dir, filename);
 		//description
 		poolItem.setDescription(comment);
@@ -200,6 +234,9 @@ class QTIImportProcessor {
 			QItemType defType = qItemTypeDao.loadByType(QuestionType.UNKOWN.name());
 			poolItem.setType(defType);
 		}
+		if(docInfos != null) {
+			processSidecarMetadata(poolItem, docInfos);
+		}
 		questionItemDao.persist(owner, poolItem);
 		return poolItem;
 	}
@@ -284,9 +321,9 @@ class QTIImportProcessor {
 	 * @param item
 	 * @param itemEl
 	 */
-	protected void processFiles(QuestionItemImpl item, ItemInfos itemInfos) {
+	protected void processFiles(QuestionItemImpl item, ItemInfos itemInfos, DocInfos docInfos) {
 		if(itemInfos.originalItem) {
-			processItemFiles(item);
+			processItemFiles(item, docInfos);
 		} else {
 			//an assessment package
 			processAssessmentFiles(item, itemInfos);
@@ -469,12 +506,22 @@ class QTIImportProcessor {
 	 * @param item
 	 * @param itemInfos
 	 */
-	protected void processItemFiles(QuestionItemImpl item) {
+	protected void processItemFiles(QuestionItemImpl item, DocInfos docInfos) {
 	//a package with an item
 		String dir = item.getDirectory();
 		String rootFilename = item.getRootFilename();
 		VFSContainer container = qpoolFileStorage.getContainer(dir);
-		if(importedFilename.toLowerCase().endsWith(".zip")) {
+		
+		if(docInfos != null && docInfos.getRoot() != null) {
+			try {
+				Path destDir = ((LocalImpl)container).getBasefile().toPath();
+				//unzip to container
+				Path path = docInfos.getRoot();
+				Files.walkFileTree(path, new CopyVisitor(path, destDir, new YesMatcher()));
+			} catch (IOException e) {
+				log.error("", e);
+			}
+		} else if(importedFilename.toLowerCase().endsWith(".zip")) {
 			ZipUtil.unzipStrict(importedFile, container);
 		} else {
 			VFSLeaf endFile = container.createChildLeaf(rootFilename);
@@ -494,6 +541,23 @@ class QTIImportProcessor {
 		}
 	}
 	
+	private boolean processSidecarMetadata(QuestionItemImpl item, DocInfos docInfos) {
+		try {
+			Path path = docInfos.root;
+			Path metadata = path.resolve(path.getFileName().toString() + "_metadata.xml");
+			InputStream metadataIn = Files.newInputStream(metadata);
+			SAXReader reader = new SAXReader();
+	        Document document = reader.read(metadataIn);
+	        Element rootElement = document.getRootElement();
+	        QTIMetadata enricher = new QTIMetadata(rootElement, qItemTypeDao, taxonomyLevelDao, qEduContextDao);
+	        enricher.toQuestion(item);
+	        return true;
+		} catch (Exception e) {
+			log.error("", e);
+			return false;
+		}
+	}
+	
 	private boolean processItemQuestionType(QuestionItemImpl poolItem, String ident, Element itemEl) {
 		boolean openolatFormat = false;
 		
@@ -545,12 +609,13 @@ class QTIImportProcessor {
 		return el.getText();
 	}
 	
-	protected DocInfos getDocInfos() throws IOException {
-		DocInfos doc;
+	protected List<DocInfos> getDocInfos() throws IOException {
+		List<DocInfos> doc;
 		if(importedFilename.toLowerCase().endsWith(".zip")) {
-			doc = traverseZip(importedFile);
+			//doc = traverseZip(importedFile);
+			doc = traverseZip_nio(importedFile);
 		} else {
-			doc = traverseFile(importedFile);
+			doc = Collections.singletonList(traverseFile(importedFile));
 		}
 		return doc;
 	}
@@ -574,32 +639,81 @@ class QTIImportProcessor {
 		}
 	}
 	
-	private DocInfos traverseZip(File file) throws IOException {
+	/*
+	private List<DocInfos> traverseZip(File file) throws IOException {
 		InputStream in = new FileInputStream(file);
 		ZipInputStream zis = new ZipInputStream(in);
+		List<DocInfos> docInfos = new ArrayList<>();
 
 		ZipEntry entry;
 		try {
 			while ((entry = zis.getNextEntry()) != null) {
 				String name = entry.getName();
 				if(name != null && name.toLowerCase().endsWith(".xml")) {
-					Document doc = readXml(zis);
+					Document doc = readXml(new ShieldInputStream(zis));
 					if(doc != null) {
 						DocInfos d = new DocInfos();
 						d.doc = doc;
 						d.filename = name;
-						return d;
+						docInfos.add(d);
 					}
 				}
 			}
-			return null;
 		} catch(Exception e) {
 			log.error("", e);
-			return null;
 		} finally {
 			IOUtils.closeQuietly(zis);
 			IOUtils.closeQuietly(in);
 		}
+		return docInfos;
+	}
+	*/
+	
+	private List<DocInfos> traverseZip_nio(File file) throws IOException {
+		List<DocInfos> docInfos = new ArrayList<>();
+		
+		Path fPath = FileSystems.newFileSystem(file.toPath(), null).getPath("/");
+		if(fPath != null) {
+			DocInfosVisitor visitor = new DocInfosVisitor();
+		    Files.walkFileTree(fPath, visitor);
+		    
+		    List<Path> xmlFiles = visitor.getXmlFiles();
+		    for(Path xmlFile:xmlFiles) {
+		    	InputStream in = Files.newInputStream(xmlFile);
+		    	
+		    	Document doc = readXml(in);
+				if(doc != null) {
+					DocInfos d = new DocInfos();
+					d.setDocument(doc);
+					d.setRoot(xmlFile.getParent());
+					d.setFilename(xmlFile.getFileName().toString());
+					docInfos.add(d);
+				}
+		    	
+		    }
+		}
+		
+		
+		return docInfos;
+	}
+	
+	public static class DocInfosVisitor extends SimpleFileVisitor<Path> {
+		
+		private final List<Path> xmlFiles = new ArrayList<>();
+		
+		public List<Path> getXmlFiles() {
+			return xmlFiles;
+		}
+
+		@Override
+		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+		throws IOException {
+			String name = file.getFileName().toString();
+			if(name != null && name.toLowerCase().endsWith(".xml")) {
+				xmlFiles.add(file);
+			}
+	        return FileVisitResult.CONTINUE;
+		}
 	}
 	
 	private Document readXml(InputStream in) {
@@ -643,6 +757,8 @@ class QTIImportProcessor {
 	public static class DocInfos {
 		private Document doc;
 		private String filename;
+		private Path root;
+		private Path metadata;
 		private String qtiComment;
 		
 		public String getFilename() {
@@ -661,6 +777,22 @@ class QTIImportProcessor {
 			this.doc = doc;
 		}
 
+		public Path getMetadata() {
+			return metadata;
+		}
+
+		public void setMetadata(Path metadata) {
+			this.metadata = metadata;
+		}
+
+		public Path getRoot() {
+			return root;
+		}
+
+		public void setRoot(Path root) {
+			this.root = root;
+		}
+
 		public String getQtiComment() {
 			return qtiComment;
 		}
diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIMetadata.java b/src/main/java/org/olat/ims/qti/qpool/QTIMetadata.java
new file mode 100644
index 0000000000000000000000000000000000000000..75a886f79ccc740f1b279f68bdaf630c39fc4ff5
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti/qpool/QTIMetadata.java
@@ -0,0 +1,306 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.ims.qti.qpool;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.dom4j.Element;
+import org.olat.core.util.StringHelper;
+import org.olat.modules.qpool.QuestionItemFull;
+import org.olat.modules.qpool.QuestionStatus;
+import org.olat.modules.qpool.TaxonomyLevel;
+import org.olat.modules.qpool.manager.QEducationalContextDAO;
+import org.olat.modules.qpool.manager.QItemTypeDAO;
+import org.olat.modules.qpool.manager.TaxonomyLevelDAO;
+import org.olat.modules.qpool.model.QEducationalContext;
+import org.olat.modules.qpool.model.QItemType;
+import org.olat.modules.qpool.model.QLicense;
+import org.olat.modules.qpool.model.QuestionItemImpl;
+
+/**
+ * 
+ * Initial date: 10.09.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+class QTIMetadata {
+	
+	private Element qtimetadata;
+	
+	private QItemTypeDAO itemTypeDao;
+	private TaxonomyLevelDAO taxonomyLevelDao;
+	private QEducationalContextDAO educationalContextDao;
+	
+	QTIMetadata(Element qtimetadata) {
+		this.qtimetadata = qtimetadata;
+	}
+	
+	QTIMetadata(Element qtimetadata, QItemTypeDAO itemTypeDao,
+			TaxonomyLevelDAO taxonomyLevelDao, QEducationalContextDAO educationalContextDao) {
+		this.qtimetadata = qtimetadata;
+		this.itemTypeDao = itemTypeDao;
+		this.taxonomyLevelDao = taxonomyLevelDao;
+		this.educationalContextDao = educationalContextDao;
+	}
+	
+	private QItemType toType(String itemType) {
+		QItemType type = itemTypeDao.loadByType(itemType);
+		if(type == null) {
+			type = itemTypeDao.create(itemType, true);
+		}
+		return type;
+	}
+	
+	private QLicense toLicense(String str) {
+		return null;
+	}
+	
+	private TaxonomyLevel toTaxonomy(String str) {
+		String[] path = str.split("/");
+		List<String> cleanedPath = new ArrayList<>(path.length);
+		for(String segment:path) {
+			if(StringHelper.containsNonWhitespace(segment)) {
+				cleanedPath.add(segment);
+			}
+		}
+		
+		TaxonomyLevel lowerLevel = null;
+		if(path != null && path.length > 0) {
+			for(String field :cleanedPath) {
+				TaxonomyLevel level = taxonomyLevelDao.loadLevelBy(lowerLevel, field);
+				if(level == null) {
+					level = taxonomyLevelDao.createAndPersist(lowerLevel, field);
+				}
+				lowerLevel = level;
+			}
+		}
+		return lowerLevel;
+	}
+	
+	private QEducationalContext toEducationalContext(String txt) {
+		QEducationalContext context = educationalContextDao.loadByLevel(txt);
+		if(context == null) {
+			context = educationalContextDao.create(txt, true);
+		}
+		return context;
+	}
+	
+	protected void toQuestion(QuestionItemImpl fullItem) {
+		String addInfos = this.getMetadataEntry("additional_informations");
+		if(StringHelper.containsNonWhitespace(addInfos)) {
+			fullItem.setAdditionalInformations(addInfos);
+		}
+		String assessmentType = getMetadataEntry("oo_assessment_type");
+		if(StringHelper.containsNonWhitespace(assessmentType)) {
+			fullItem.setAssessmentType(assessmentType);
+		}
+		String coverage = getMetadataEntry("coverage");
+		if(StringHelper.containsNonWhitespace(coverage)) {
+			fullItem.setCoverage(coverage);
+		}
+		String description = getMetadataEntry("description");
+		if(description != null) {
+			fullItem.setDescription(description);
+		}
+		String differentiation = getMetadataEntry("oo_differentiation");
+		if(StringHelper.containsNonWhitespace(differentiation)) {
+			fullItem.setDifferentiation(toBigDecimal(differentiation));
+		}
+		String difficulty = getMetadataEntry("qmd_levelofdifficulty");
+		if(StringHelper.containsNonWhitespace(difficulty)) {
+			fullItem.setDifficulty(toBigDecimal(difficulty));
+		}
+		String vendor = getMetadataEntry("qmd_toolvendor");
+		if(vendor != null) {
+			fullItem.setEditor(vendor);
+		}
+		String editorVersion = getMetadataEntry("oo_toolvendor_version");
+		if(StringHelper.containsNonWhitespace(editorVersion)) {
+			fullItem.setEditorVersion(editorVersion);
+		}
+		String learningTime = getMetadataEntry("oo_education_learning_time");
+		if(StringHelper.containsNonWhitespace(learningTime)) {
+			fullItem.setEducationalLearningTime(learningTime);
+		}
+		String format = getMetadataEntry("format");
+		if(StringHelper.containsNonWhitespace(format)) {
+			fullItem.setFormat(format);
+		}
+		String identifier = getMetadataEntry("oo_identifier");
+		if(StringHelper.containsNonWhitespace(identifier)) {
+			fullItem.setMasterIdentifier(identifier);
+		}
+		String itemType = getMetadataEntry("type");
+		if(StringHelper.containsNonWhitespace(itemType)) {
+			fullItem.setType(toType(itemType));
+		}
+		String version = getMetadataEntry("version");
+		if(StringHelper.containsNonWhitespace(version)) {
+			fullItem.setItemVersion(version);
+		}
+		String keywords = getMetadataEntry("keywords");
+		if(StringHelper.containsNonWhitespace(keywords)) {
+			fullItem.setKeywords(keywords);
+		}
+		String language = getMetadataEntry("language");
+		if(StringHelper.containsNonWhitespace(language)) {
+			fullItem.setLanguage(language);
+		}
+		String numOfAnswers = getMetadataEntry("oo_num_of_answer_alternatives");
+		if(StringHelper.containsNonWhitespace(numOfAnswers)) {
+			fullItem.setNumOfAnswerAlternatives(toInt(numOfAnswers));
+		}
+		String status = getMetadataEntry("status");
+		if(StringHelper.containsNonWhitespace(status) && validStatus(status)) {
+			fullItem.setStatus(status);
+		}
+		String stdDevDifficulty = getMetadataEntry("oo_std_dev_difficulty");
+		if(StringHelper.containsNonWhitespace(stdDevDifficulty)) {
+			fullItem.setStdevDifficulty(toBigDecimal(stdDevDifficulty));
+		}
+		String title = getMetadataEntry("title");
+		if(StringHelper.containsNonWhitespace(title)) {
+			fullItem.setTitle(title);
+		}
+		String license = getMetadataEntry("license");
+		if(StringHelper.containsNonWhitespace(license)) {
+			fullItem.setLicense(toLicense(license));
+		}
+		String taxonomy = getMetadataEntry("oo_taxonomy");
+		if(StringHelper.containsNonWhitespace(taxonomy)) {
+			fullItem.setTaxonomyLevel(toTaxonomy(taxonomy));
+		}
+		String educationalContext = getMetadataEntry("oo_educational_context");
+		if(StringHelper.containsNonWhitespace(educationalContext)) {
+			fullItem.setEducationalContext(toEducationalContext(educationalContext));
+		}
+	}
+	
+	protected void toXml(QuestionItemFull fullItem) {
+		addMetadataField("additional_informations", fullItem.getAdditionalInformations(), qtimetadata);
+		addMetadataField("oo_assessment_type", fullItem.getAssessmentType(), qtimetadata);
+		addMetadataField("coverage", fullItem.getCoverage(), qtimetadata);
+		addMetadataField("description", fullItem.getDescription(), qtimetadata);
+		addMetadataField("oo_differentiation", fullItem.getDifferentiation(), qtimetadata);
+		addMetadataField("qmd_levelofdifficulty", fullItem.getDifficulty(), qtimetadata);
+		addMetadataField("qmd_toolvendor", fullItem.getEditor(), qtimetadata);
+		addMetadataField("oo_toolvendor_version", fullItem.getEditorVersion(), qtimetadata);
+		addMetadataField("oo_educational_context", fullItem.getEducationalContext(), qtimetadata);
+		addMetadataField("oo_education_learning_time", fullItem.getEducationalLearningTime(), qtimetadata);
+		addMetadataField("format", fullItem.getFormat(), qtimetadata);
+		addMetadataField("oo_identifier", fullItem.getIdentifier(), qtimetadata);
+		addMetadataField("type", fullItem.getItemType(), qtimetadata);
+		addMetadataField("version", fullItem.getItemVersion(), qtimetadata);
+		addMetadataField("keywords", fullItem.getKeywords(), qtimetadata);
+		addMetadataField("language", fullItem.getLanguage(), qtimetadata);
+		addMetadataField("license", fullItem.getLicense(), qtimetadata);
+		addMetadataField("oo_master", fullItem.getMasterIdentifier(), qtimetadata);
+		addMetadataField("oo_num_of_answer_alternatives", fullItem.getNumOfAnswerAlternatives(), qtimetadata);
+		addMetadataField("status", fullItem.getQuestionStatus(), qtimetadata);
+		addMetadataField("oo_std_dev_difficulty", fullItem.getStdevDifficulty(), qtimetadata);
+		addMetadataField("oo_taxonomy", fullItem.getTaxonomicPath(), qtimetadata);
+		//fullItem.getTaxonomicLevel();
+		addMetadataField("title", fullItem.getTitle(), qtimetadata);
+		addMetadataField("oo_usage", fullItem.getUsage(), qtimetadata);
+	}
+	
+	private void addMetadataField(String label, int entry, Element qtimetadata) {
+		if(entry >=  0) {
+			addMetadataField(label, Integer.toString(entry), qtimetadata);
+		}
+	}
+	
+	private void addMetadataField(String label, QLicense entry, Element qtimetadata) {
+		if(entry != null) {
+			addMetadataField(label, entry.getLicenseText(), qtimetadata);
+		}
+	}
+	
+	private void addMetadataField(String label, QEducationalContext entry, Element qtimetadata) {
+		if(entry != null) {
+			addMetadataField(label, entry.getLevel(), qtimetadata);
+		}
+	}
+	
+	private void addMetadataField(String label, QuestionStatus entry, Element qtimetadata) {
+		if(entry != null) {
+			addMetadataField(label, entry.name(), qtimetadata);
+		}
+	}
+	
+	private void addMetadataField(String label, BigDecimal entry, Element qtimetadata) {
+		if(entry != null) {
+			addMetadataField(label, entry.toPlainString(), qtimetadata);
+		}
+	}
+	
+	private void addMetadataField(String label, String entry, Element qtimetadata) {
+		if(entry != null) {
+			Element qtimetadatafield = qtimetadata.addElement("qtimetadatafield");
+			qtimetadatafield.addElement("fieldlabel").setText(label);
+			qtimetadatafield.addElement("fieldentry").setText(entry);
+		}
+	}
+	
+	private String getMetadataEntry(String label) {
+		String entry = null;
+		
+		@SuppressWarnings("unchecked")
+		List<Element> qtimetadatafields = qtimetadata.elements("qtimetadatafield");
+		for(Element qtimetadatafield:qtimetadatafields) {
+			Element fieldlabel = qtimetadatafield.element("fieldlabel");
+			if(fieldlabel != null && label.equals(fieldlabel.getText())) {
+				Element fieldentry = qtimetadatafield.element("fieldentry");
+				if(fieldentry != null) {
+					entry = fieldentry.getText();
+				}
+			}
+		}
+		
+		return entry;
+	}
+	
+	private BigDecimal toBigDecimal(String str) {
+		try {
+			return new BigDecimal(str);
+		} catch (Exception e) {
+			return null;
+		}
+	}
+	
+	private int toInt(String str) {
+		try {
+			return Integer.parseInt(str);
+		} catch (NumberFormatException e) {
+			return 0;
+		}
+	}
+	
+	private boolean validStatus(String str) {
+		try {
+			QuestionStatus.valueOf(str);
+			return true;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java
index aae2920f58f1c104aa2d76537e29ef612d62b339..62cab9fbac5964d996e6efd6cfaebd54accd80cd 100644
--- a/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java
+++ b/src/main/java/org/olat/ims/qti/qpool/QTIQPoolServiceProvider.java
@@ -71,6 +71,7 @@ import org.olat.modules.qpool.manager.QEducationalContextDAO;
 import org.olat.modules.qpool.manager.QItemTypeDAO;
 import org.olat.modules.qpool.manager.QPoolFileStorage;
 import org.olat.modules.qpool.manager.QuestionItemDAO;
+import org.olat.modules.qpool.manager.TaxonomyLevelDAO;
 import org.olat.modules.qpool.model.DefaultExportFormat;
 import org.olat.modules.qpool.model.QuestionItemImpl;
 import org.olat.repository.RepositoryEntry;
@@ -103,6 +104,8 @@ public class QTIQPoolServiceProvider implements QPoolSPI {
 	private QuestionItemDAO questionItemDao;
 	@Autowired
 	private QEducationalContextDAO qEduContextDao;
+	@Autowired
+	private TaxonomyLevelDAO taxonomyLevelDao;
 	
 	private static final List<ExportFormatOptions> formats = new ArrayList<ExportFormatOptions>(2);
 	static {
@@ -185,7 +188,7 @@ public class QTIQPoolServiceProvider implements QPoolSPI {
 	@Override
 	public List<QuestionItem> importItems(Identity owner, Locale defaultLocale, String filename, File file) {
 		QTIImportProcessor processor = new QTIImportProcessor(owner, defaultLocale, filename, file,
-				questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		return processor.process();
 	}
 	
@@ -215,11 +218,11 @@ public class QTIQPoolServiceProvider implements QPoolSPI {
 		item.setTitle(title);
 		
 		QTIImportProcessor processor = new QTIImportProcessor(owner, defaultLocale,
-				questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		
 		Document doc = QTIEditHelper.itemToXml(item);
 		Element itemEl = (Element)doc.selectSingleNode("questestinterop/item");
-		QuestionItemImpl qitem = processor.processItem(itemEl, "", null, "OpenOLAT", Settings.getVersion());
+		QuestionItemImpl qitem = processor.processItem(itemEl, "", null, "OpenOLAT", Settings.getVersion(), null);
 		//save to file System
 		VFSContainer baseDir = qpoolFileStorage.getContainer(qitem.getDirectory());
 		VFSLeaf leaf = baseDir.createChildLeaf(qitem.getRootFilename());
@@ -229,7 +232,7 @@ public class QTIQPoolServiceProvider implements QPoolSPI {
 	
 	public void importBeecomItem(Identity owner, Item item, VFSContainer sourceDir, Locale defaultLocale) {
 		QTIImportProcessor processor = new QTIImportProcessor(owner, defaultLocale,
-				questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		
 		String editor = null;
 		String editorVersion = null;
@@ -240,7 +243,7 @@ public class QTIQPoolServiceProvider implements QPoolSPI {
 		
 		Document doc = QTIEditHelper.itemToXml(item);
 		Element itemEl = (Element)doc.selectSingleNode("questestinterop/item");
-		QuestionItemImpl qitem = processor.processItem(itemEl, "", null, editor, editorVersion);
+		QuestionItemImpl qitem = processor.processItem(itemEl, "", null, editor, editorVersion, null);
 		//save to file System
 		VFSContainer baseDir = qpoolFileStorage.getContainer(qitem.getDirectory());
 		VFSLeaf leaf = baseDir.createChildLeaf(qitem.getRootFilename());
diff --git a/src/main/java/org/olat/modules/qpool/manager/TaxonomyLevelDAO.java b/src/main/java/org/olat/modules/qpool/manager/TaxonomyLevelDAO.java
index b1f0bef9c7ca37703b832aaf5d89798843410202..17a31c996eeb3ff3be0f55358821b332b7358fb7 100644
--- a/src/main/java/org/olat/modules/qpool/manager/TaxonomyLevelDAO.java
+++ b/src/main/java/org/olat/modules/qpool/manager/TaxonomyLevelDAO.java
@@ -22,6 +22,8 @@ package org.olat.modules.qpool.manager;
 import java.util.Date;
 import java.util.List;
 
+import javax.persistence.TypedQuery;
+
 import org.olat.core.commons.persistence.DB;
 import org.olat.modules.qpool.TaxonomyLevel;
 import org.olat.modules.qpool.model.TaxonomyLevelImpl;
@@ -126,6 +128,28 @@ public class TaxonomyLevelDAO {
 				.setParameter("path", path + "%")
 				.getResultList();
 	}
+	
+	public TaxonomyLevel loadLevelBy(TaxonomyLevel parent, String field) {
+		TypedQuery<TaxonomyLevel> query;
+		if(parent == null) {
+			String q = "select f from qtaxonomylevel f where f.field=:field and f.parentField is null";
+			query = dbInstance.getCurrentEntityManager()
+				.createQuery(q, TaxonomyLevel.class);
+				
+		} else {
+			String q = "select f from qtaxonomylevel f where f.field=:field and f.parentField=:parent";
+			query = dbInstance.getCurrentEntityManager()
+				.createQuery(q, TaxonomyLevel.class)
+				.setParameter("parent", parent);
+		}
+		List<TaxonomyLevel> fields = query
+				.setParameter("field", field)
+				.getResultList();
+		if(fields.isEmpty()) {
+			return null;
+		}
+		return fields.get(0);
+	}
 
 	
 	public TaxonomyLevel loadLevelById(Long key) {
diff --git a/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java b/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java
index c34cd93ded8f4ba321154a52041b51f23798a3b4..b49f5c16fefa91dd033d43b9b353c60cd996577e 100644
--- a/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java
+++ b/src/test/java/org/olat/ims/qti/qpool/QTIExportProcessorTest.java
@@ -40,10 +40,11 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.modules.qpool.QuestionItem;
 import org.olat.modules.qpool.QuestionItemFull;
-import org.olat.modules.qpool.manager.QPoolFileStorage;
 import org.olat.modules.qpool.manager.QEducationalContextDAO;
 import org.olat.modules.qpool.manager.QItemTypeDAO;
+import org.olat.modules.qpool.manager.QPoolFileStorage;
 import org.olat.modules.qpool.manager.QuestionItemDAO;
+import org.olat.modules.qpool.manager.TaxonomyLevelDAO;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -67,6 +68,8 @@ public class QTIExportProcessorTest extends OlatTestCase {
 	@Autowired
 	private QuestionItemDAO questionItemDao;
 	@Autowired
+	private TaxonomyLevelDAO taxonomyLevelDao;
+	@Autowired
 	private QEducationalContextDAO qEduContextDao;
 	
 	@Before
@@ -83,7 +86,8 @@ public class QTIExportProcessorTest extends OlatTestCase {
 		URL itemUrl = QTIExportProcessorTest.class.getResource("mchc_asmimr_106.zip");
 		Assert.assertNotNull(itemUrl);
 		File itemFile = new File(itemUrl.toURI());
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		List<QuestionItem> items = proc.process();
 		Assert.assertNotNull(items);
 		dbInstance.commitAndCloseSession();
diff --git a/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java b/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java
index 95352b76fadb48698477f3f0ac16fe3866d57ba6..3d7dc08d5da7869a08ffc97a37cad7c5588b2583 100644
--- a/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java
+++ b/src/test/java/org/olat/ims/qti/qpool/QTIImportProcessorTest.java
@@ -22,6 +22,7 @@ package org.olat.ims.qti.qpool;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.math.BigDecimal;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.List;
@@ -53,6 +54,7 @@ import org.olat.modules.qpool.manager.QEducationalContextDAO;
 import org.olat.modules.qpool.manager.QItemTypeDAO;
 import org.olat.modules.qpool.manager.QPoolFileStorage;
 import org.olat.modules.qpool.manager.QuestionItemDAO;
+import org.olat.modules.qpool.manager.TaxonomyLevelDAO;
 import org.olat.modules.qpool.model.QEducationalContext;
 import org.olat.modules.qpool.model.QItemType;
 import org.olat.modules.qpool.model.QuestionItemImpl;
@@ -79,6 +81,8 @@ public class QTIImportProcessorTest extends OlatTestCase {
 	@Autowired
 	private QuestionItemDAO questionItemDao;
 	@Autowired
+	private TaxonomyLevelDAO taxonomyLevelDao;
+	@Autowired
 	private QEducationalContextDAO qEduContextDao;
 	
 	@Before
@@ -100,8 +104,13 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File itemFile = new File(itemUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
-		DocInfos docInfos = proc.getDocInfos();
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
+		List<DocInfos> docInfoList = proc.getDocInfos();
+		Assert.assertNotNull(docInfoList);
+		Assert.assertEquals(1, docInfoList.size());
+		
+		DocInfos docInfos = docInfoList.get(0);
 		Assert.assertNotNull(docInfos);
 		Assert.assertNotNull(docInfos.getFilename());
 		Assert.assertNotNull(docInfos.getDocument());
@@ -116,7 +125,7 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		QuestionItemImpl item = proc.processItem(docInfos, itemInfos.get(0));
 		Assert.assertNotNull(item);
 		dbInstance.commitAndCloseSession();
-		proc.processFiles(item, itemInfos.get(0));
+		proc.processFiles(item, itemInfos.get(0), null);
 		
 		//reload and check what is saved
 		QuestionItemFull reloadItem = questionItemDao.loadById(item.getKey());
@@ -150,7 +159,8 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File itemFile = new File(itemUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		List<QuestionItem> items = proc.process();
 		Assert.assertNotNull(items);
 		Assert.assertEquals(1, items.size());
@@ -183,8 +193,13 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File testFile = new File(testUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, testFile.getName(), testFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
-		DocInfos docInfos = proc.getDocInfos();
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, testFile.getName(), testFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
+		List<DocInfos> docInfoList = proc.getDocInfos();
+		Assert.assertNotNull(docInfoList);
+		Assert.assertEquals(1, docInfoList.size());
+		
+		DocInfos docInfos = docInfoList.get(0);
 		Assert.assertNotNull(docInfos);
 		Assert.assertNotNull(docInfos.getFilename());
 		Assert.assertNotNull(docInfos.getDocument());
@@ -203,7 +218,8 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File itemFile = new File(itemUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		List<QuestionItem> items = proc.process();
 		Assert.assertNotNull(items);
 		Assert.assertEquals(4, items.size());
@@ -265,7 +281,8 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File itemFile = new File(itemUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		List<QuestionItem> items = proc.process();
 		Assert.assertNotNull(items);
 		Assert.assertEquals(2, items.size());
@@ -311,7 +328,8 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File itemFile = new File(itemUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		List<QuestionItem> items = proc.process();
 		Assert.assertNotNull(items);
 		Assert.assertEquals(3, items.size());
@@ -357,6 +375,51 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		}
 	}
 	
+	@Test
+	public void testImport_QTI12_multipleItems() throws IOException, URISyntaxException {
+		URL itemsUrl = QTIImportProcessorTest.class.getResource("multiple_items.zip");
+		Assert.assertNotNull(itemsUrl);
+		File itemFile = new File(itemsUrl.toURI());
+		
+		//get the document informations
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
+		List<QuestionItem> items = proc.process();
+		Assert.assertNotNull(items);
+		Assert.assertEquals(2, items.size());
+		dbInstance.commitAndCloseSession();
+		
+		//check the files
+		for(QuestionItem item:items) {
+			QuestionItemFull itemFull = (QuestionItemFull)item;
+			String dir = itemFull.getDirectory();
+			String file = itemFull.getRootFilename();
+			VFSContainer itemContainer = qpoolFileStorage.getContainer(dir);
+			Assert.assertNotNull(itemContainer);
+			VFSItem itemLeaf = itemContainer.resolve(file);
+			Assert.assertNotNull(itemLeaf);
+			Assert.assertTrue(itemLeaf instanceof VFSLeaf);
+			
+			//try to parse it
+			InputStream is = ((VFSLeaf)itemLeaf).getInputStream();
+			XMLParser xmlParser = new XMLParser(new IMSEntityResolver());
+			Document doc = xmlParser.parse(is, false);
+			Node itemNode = doc.selectSingleNode("questestinterop/item");
+			Assert.assertNotNull(itemNode);
+			
+			//check the attachments
+			if("Export (blue)".equals(itemFull.getTitle())) {
+				Assert.assertTrue(exists(itemFull, "media/blue.png"));
+				Assert.assertFalse(exists(itemFull, "media/purple.png"));
+			} else if("Export (purple)".equals(itemFull.getTitle())) {
+				Assert.assertFalse(exists(itemFull, "media/blue.png"));
+				Assert.assertTrue(exists(itemFull, "media/purple.png"));
+			} else {
+				Assert.fail();
+			}
+		}
+	}
+	
 	@Test
 	public void testImport_QTI12_metadata() throws IOException, URISyntaxException {
 		URL itemUrl = QTIImportProcessorTest.class.getResource("mchc_i_001.xml");
@@ -364,7 +427,8 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File itemFile = new File(itemUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		List<QuestionItem> items = proc.process();
 		Assert.assertNotNull(items);
 		Assert.assertEquals(1, items.size());
@@ -381,6 +445,49 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		Assert.assertEquals("QTITools", item.getEditor());	
 	}
 	
+	@Test
+	public void testImport_QTI12_sidecarMetadata() throws IOException, URISyntaxException {
+		URL itemUrl = QTIImportProcessorTest.class.getResource("qitem_metadatas.zip");
+		Assert.assertNotNull(itemUrl);
+		File itemFile = new File(itemUrl.toURI());
+		
+		//get the document informations
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
+		List<QuestionItem> items = proc.process();
+		Assert.assertNotNull(items);
+		Assert.assertEquals(1, items.size());
+		dbInstance.commitAndCloseSession();
+
+		//reload and check metadata
+		QuestionItem item = questionItemDao.loadById(items.get(0).getKey());
+		Assert.assertEquals("Une information en plus", item.getAdditionalInformations());
+		Assert.assertEquals("formative", item.getAssessmentType());
+		Assert.assertEquals("large", item.getCoverage());
+		Assert.assertEquals(0, new BigDecimal("-0.1").compareTo(item.getDifferentiation()));
+		Assert.assertEquals(0, new BigDecimal("0.45").compareTo(item.getDifficulty()));
+		Assert.assertEquals("OpenOLAT", item.getEditor());
+		Assert.assertEquals("9.4", item.getEditorVersion());
+		QEducationalContext level = item.getEducationalContext();
+		Assert.assertNotNull(level);
+		Assert.assertEquals("University", level.getLevel());
+		Assert.assertEquals("P5DT4H3M2S", item.getEducationalLearningTime());
+		Assert.assertEquals("IMS QTI 1.2", item.getFormat());
+		Assert.assertEquals("6bae65ac-f333-40ba-bdd0-13b54d016d59", item.getMasterIdentifier());
+		Assert.assertFalse("6bae65ac-f333-40ba-bdd0-13b54d016d59".equals(item.getIdentifier()));
+		Assert.assertEquals("sc", item.getItemType());
+		Assert.assertEquals("1.01", item.getItemVersion());
+		Assert.assertEquals("question export import Pluton", item.getKeywords());
+		Assert.assertEquals("de", item.getLanguage());
+		Assert.assertEquals(1, item.getNumOfAnswerAlternatives());
+		Assert.assertNotNull(item.getQuestionStatus());
+		Assert.assertEquals("review", item.getQuestionStatus().name());
+		Assert.assertEquals(0, new BigDecimal("0.56").compareTo(item.getStdevDifficulty()));
+		Assert.assertEquals("/Physique/Astronomie/Astrophysique", item.getTaxonomicPath());
+		Assert.assertEquals("Une question sur Pluton", item.getTitle());
+		Assert.assertEquals(0, item.getUsage());
+	}
+	
 	@Test
 	public void testImport_QTI12_film() throws IOException, URISyntaxException {
 		URL itemUrl = QTIImportProcessorTest.class.getResource("sc_with_film.xml");
@@ -388,11 +495,16 @@ public class QTIImportProcessorTest extends OlatTestCase {
 		File itemFile = new File(itemUrl.toURI());
 		
 		//get the document informations
-		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile, questionItemDao, qItemTypeDao, qEduContextDao, qpoolFileStorage);
+		QTIImportProcessor proc = new QTIImportProcessor(owner, Locale.ENGLISH, itemFile.getName(), itemFile,
+				questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qpoolFileStorage, dbInstance);
 		List<QuestionItem> items = proc.process();
 		Assert.assertNotNull(items);
 		
-		DocInfos docInfos = proc.getDocInfos();
+		List<DocInfos> docInfoList = proc.getDocInfos();
+		Assert.assertNotNull(docInfoList);
+		Assert.assertEquals(1, docInfoList.size());
+		
+		DocInfos docInfos = docInfoList.get(0);
 		List<ItemInfos> itemInfos = proc.getItemList(docInfos);
 		Assert.assertNotNull(itemInfos);
 		Assert.assertEquals(1, itemInfos.size());
diff --git a/src/test/java/org/olat/ims/qti/qpool/multiple_items.zip b/src/test/java/org/olat/ims/qti/qpool/multiple_items.zip
new file mode 100644
index 0000000000000000000000000000000000000000..6e23a54a87e790b09586467c3323bb78c6e6b7b0
Binary files /dev/null and b/src/test/java/org/olat/ims/qti/qpool/multiple_items.zip differ
diff --git a/src/test/java/org/olat/ims/qti/qpool/qitem_metadatas.zip b/src/test/java/org/olat/ims/qti/qpool/qitem_metadatas.zip
new file mode 100644
index 0000000000000000000000000000000000000000..aa7abd90c694eea11c1dd5e5218462ea4ef99cb5
Binary files /dev/null and b/src/test/java/org/olat/ims/qti/qpool/qitem_metadatas.zip differ