diff --git a/src/main/java/org/olat/ims/qti21/QTI21Service.java b/src/main/java/org/olat/ims/qti21/QTI21Service.java
index e4465d5d4a25617af92bdc1f26ba716e57125cdd..13fdf1bf1649547dd35458991e37ccf81aa4e822 100644
--- a/src/main/java/org/olat/ims/qti21/QTI21Service.java
+++ b/src/main/java/org/olat/ims/qti21/QTI21Service.java
@@ -96,7 +96,8 @@ public interface QTI21Service {
 	
 	/**
 	 * Load the assessmentTest based on the imsmanifest.xml found in the resource
-	 * directory. Return null if the imsmanifest.xml is not found.
+	 * directory. Return null if the imsmanifest.xml is not found. The assessmentTest
+	 * is cached.
 	 * 
 	 * @param resourceDirectory The directory where is the package
 	 * @param replace If true updates the cache
@@ -105,8 +106,25 @@ public interface QTI21Service {
 	 */
 	public ResolvedAssessmentTest loadAndResolveAssessmentTest(File resourceDirectory, boolean replace, boolean debugInfo);
 	
+	/**
+	 * The assessment item is load and cached.
+	 * 
+	 * @param assessmentObjectSystemId
+	 * @param resourceDirectory
+	 * @return
+	 */
 	public ResolvedAssessmentItem loadAndResolveAssessmentItem(URI assessmentObjectSystemId, File resourceDirectory);
 	
+	/**
+	 * This method load a fresh instance from the disk and don't cache it. The instance can be changed and saved
+	 * safely.
+	 * 
+	 * @param assessmentObjectSystemId
+	 * @param resourceDirectory
+	 * @return
+	 */
+	public ResolvedAssessmentItem loadAndResolveAssessmentItemForCopy(URI assessmentObjectSystemId, File resourceDirectory);
+	
 	public boolean updateAssesmentObject(File resourceFile, ResolvedAssessmentObject<?> resolvedAssessmentObject);
 	
 	public boolean persistAssessmentObject(File resourceFile, AssessmentObject assessmentObject);
diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
index de4a1dd201112b72037bc84b19368fdbb3fa7716..3f4d3ebf6cb5ae14352c2ba91e8e77f849e69170 100644
--- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
+++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
@@ -320,16 +320,21 @@ public class QTI21ServiceImpl implements QTI21Service, UserDataDeletable, Initia
 	public ResolvedAssessmentItem loadAndResolveAssessmentItem(URI assessmentObjectSystemId, File resourceDirectory) {
 		File resourceFile = new File(assessmentObjectSystemId);
 		return assessmentItemsCache.computeIfAbsent(resourceFile, (file) -> {
-			QtiXmlReader qtiXmlReader = new QtiXmlReader(jqtiExtensionManager());
-			ResourceLocator fileResourceLocator = new PathResourceLocator(resourceDirectory.toPath());
-			ResourceLocator inputResourceLocator = 
-	        		ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator);
-			
-	        AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, inputResourceLocator);
-	       	return assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId);
+	       	return loadAndResolveAssessmentItemForCopy(assessmentObjectSystemId, resourceDirectory);
 		});
 	}
 	
+	@Override
+	public ResolvedAssessmentItem loadAndResolveAssessmentItemForCopy(URI assessmentObjectSystemId, File resourceDirectory) {
+		QtiXmlReader qtiXmlReader = new QtiXmlReader(jqtiExtensionManager());
+		ResourceLocator fileResourceLocator = new PathResourceLocator(resourceDirectory.toPath());
+		ResourceLocator inputResourceLocator = 
+        		ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator);
+		
+        AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, inputResourceLocator);
+       	return assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId);
+	}
+	
 	@Override
 	public boolean updateAssesmentObject(File resourceFile, ResolvedAssessmentObject<?> resolvedAssessmentObject) {
 		AssessmentObject assessmentObject;
diff --git a/src/main/java/org/olat/ims/qti21/pool/ImportExportHelper.java b/src/main/java/org/olat/ims/qti21/pool/ImportExportHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..7aea8beb416b11797431fa468aea63e992c53ef2
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/pool/ImportExportHelper.java
@@ -0,0 +1,141 @@
+/**
+ * <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.qti21.pool;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.util.StringHelper;
+
+import uk.ac.ed.ph.jqtiplus.node.content.xhtml.hypertext.A;
+import uk.ac.ed.ph.jqtiplus.node.content.xhtml.image.Img;
+import uk.ac.ed.ph.jqtiplus.node.content.xhtml.object.Object;
+import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
+import uk.ac.ed.ph.jqtiplus.utils.QueryUtils;
+
+/**
+ * 
+ * Initial date: 16 mars 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ImportExportHelper {
+	
+	protected static List<String> getMaterials(AssessmentItem item) {
+		List<String> materials = new ArrayList<>();
+		QueryUtils.search(Img.class, item).forEach((img) -> {
+			if(img.getSrc() != null) {
+				materials.add(img.getSrc().toString());
+			}
+		});
+		
+		QueryUtils.search(A.class, item).forEach((a) -> {
+			URI href = a.getHref();
+			if(href != null && href.getHost() == null && href.getPath() != null) {
+				materials.add(href.getPath());
+			}
+		});
+
+		QueryUtils.search(Object.class, item).forEach((object) -> {
+			if(StringHelper.containsNonWhitespace(object.getData())) {
+				materials.add(object.getData());
+			}
+		});
+		return materials;
+	}
+	
+	protected static void getMaterials(AssessmentItem item, File itemFile, AssessmentItemsAndResources materials) {
+		File directory = itemFile.getParentFile();
+
+		QueryUtils.search(Img.class, item).forEach((img) -> {
+			if(img.getSrc() != null) {
+				String imgPath = img.getSrc().toString();
+				File imgFile = new File(directory, imgPath);
+				if(imgFile.exists()) {
+					materials.addMaterial(new ItemMaterial(imgFile, imgPath));
+				}
+			}
+		});
+		
+		QueryUtils.search(A.class, item).forEach((a) -> {
+			URI href = a.getHref();
+			if(href != null && href.getHost() == null && href.getPath() != null) {
+				String hrefPath = href.getPath();
+				File aFile = new File(directory, hrefPath);
+				if(aFile.exists()) {
+					materials.addMaterial(new ItemMaterial(aFile, hrefPath));
+				}
+			}
+		});
+
+		QueryUtils.search(Object.class, item).forEach((object) -> {
+			if(StringHelper.containsNonWhitespace(object.getData())) {
+				String path = object.getData();
+				File objectFile = new File(directory, path);
+				if(objectFile.exists()) {
+					materials.addMaterial(new ItemMaterial(objectFile, path));
+				}
+			}
+		});
+	}
+	
+	public static final class AssessmentItemsAndResources {
+		private final List<ResolvedAssessmentItem> itemEls = new ArrayList<>();
+		private final List<ItemMaterial> materials = new ArrayList<>();
+		
+		public List<ResolvedAssessmentItem> getAssessmentItems() {
+			return itemEls;
+		}
+		
+		public void addItemEl(ResolvedAssessmentItem el) {
+			itemEls.add(el);
+		}
+		
+		public List<ItemMaterial> getMaterials() {
+			return materials;
+		}
+		
+		public void addMaterial(ItemMaterial material) {
+			materials.add(material);
+		}
+	}
+	
+	public static final class ItemMaterial {
+		private final File file;
+		private final String exportUri;
+		
+		public ItemMaterial(File file, String exportUri) {
+			this.file = file;
+			this.exportUri = exportUri;
+		}
+		
+		public File getFile() {
+			return file;
+		}
+		
+		public String getExportUri() {
+			return exportUri;
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java b/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java
index f6c86be73af5a0aa1ea0484ce9f8d46badc2f2d3..1ade128960c01bf9cb7464d34a0f1717fe26cfe8 100644
--- a/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java
+++ b/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java
@@ -32,6 +32,7 @@ import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.atomic.DoubleAdder;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
@@ -42,22 +43,24 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.ZipUtil;
 import org.olat.core.util.io.ShieldOutputStream;
 import org.olat.ims.qti21.QTI21Service;
+import org.olat.ims.qti21.model.QTI21QuestionType;
+import org.olat.ims.qti21.model.xml.AssessmentTestBuilder;
 import org.olat.ims.qti21.model.xml.AssessmentTestFactory;
 import org.olat.ims.qti21.model.xml.ManifestBuilder;
 import org.olat.ims.qti21.model.xml.ManifestMetadataBuilder;
+import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
+import org.olat.ims.qti21.pool.ImportExportHelper.AssessmentItemsAndResources;
+import org.olat.ims.qti21.pool.ImportExportHelper.ItemMaterial;
 import org.olat.imscp.xml.manifest.ResourceType;
 import org.olat.modules.qpool.QuestionItemFull;
 import org.olat.modules.qpool.manager.QPoolFileStorage;
 
-import uk.ac.ed.ph.jqtiplus.node.content.xhtml.image.Img;
-import uk.ac.ed.ph.jqtiplus.node.content.xhtml.object.Object;
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
 import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
 import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
 import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer;
-import uk.ac.ed.ph.jqtiplus.utils.QueryUtils;
 
 /**
  * 
@@ -97,7 +100,7 @@ public class QTI21ExportProcessor {
 		URI assessmentItemUri = resourceFile.toURI();
 		
 		ResolvedAssessmentItem resolvedAssessmentItem = qtiService
-				.loadAndResolveAssessmentItem(assessmentItemUri, rootDirectory);
+				.loadAndResolveAssessmentItemForCopy(assessmentItemUri, rootDirectory);
 		enrichWithMetadata(qitem, resolvedAssessmentItem, manifestBuilder);
 		
 		try {
@@ -154,37 +157,16 @@ public class QTI21ExportProcessor {
 		File itemFile = new File(resourceDirectory, rootFilename);
 
 		if(itemFile.exists()) {
-			ResolvedAssessmentItem assessmentItem = qtiService.loadAndResolveAssessmentItem(itemFile.toURI(), resourceDirectory);
+			ResolvedAssessmentItem resolvedAssessmentItem = qtiService.loadAndResolveAssessmentItemForCopy(itemFile.toURI(), resourceDirectory);
+			AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
 			//enrichScore(itemEl);
 			//enrichWithMetadata(fullItem, itemEl);
-			collectResources(assessmentItem.getRootNodeLookup().extractIfSuccessful(), itemFile, materials);
-			materials.addItemEl(assessmentItem);
+			ImportExportHelper.getMaterials(assessmentItem, itemFile, materials);
+			materials.addItemEl(resolvedAssessmentItem);
 		}
 	}
 	
-	protected void collectResources(AssessmentItem item, File itemFile, AssessmentItemsAndResources materials) {
-		File directory = itemFile.getParentFile();
 
-		QueryUtils.search(Img.class, item).forEach((img) -> {
-			if(img.getSrc() != null) {
-				String imgPath = img.getSrc().toString();
-				File imgFile = new File(directory, imgPath);
-				if(imgFile.exists()) {
-					materials.addMaterial(new ItemMaterial(imgFile, imgPath));
-				}
-			}
-		});
-
-		QueryUtils.search(Object.class, item).forEach((object) -> {
-			if(StringHelper.containsNonWhitespace(object.getData())) {
-				String path = object.getData();
-				File objectFile = new File(directory, path);
-				if(objectFile.exists()) {
-					materials.addMaterial(new ItemMaterial(objectFile, path));
-				}
-			}
-		});
-	}
 	
 	public void enrichWithMetadata(QuestionItemFull qitem, ResolvedAssessmentItem resolvedAssessmentItem, ManifestBuilder manifestBuilder) {
 		ResourceType resource = manifestBuilder.getResourceTypeByHref(qitem.getRootFilename());
@@ -202,6 +184,7 @@ public class QTI21ExportProcessor {
 			ManifestBuilder manifest = ManifestBuilder.createAssessmentTestBuilder();
 			
 			//assessment test
+			DoubleAdder atomicMaxScore = new DoubleAdder();
 			AssessmentTest assessmentTest = AssessmentTestFactory.createAssessmentTest("Assessment test from pool", "Section");
 			String assessmentTestFilename = assessmentTest.getIdentifier() + ".xml";
 			manifest.appendAssessmentTest(assessmentTestFilename);
@@ -211,20 +194,49 @@ public class QTI21ExportProcessor {
 
 			//assessment items
 			for(QuestionItemFull qitem:fullItems) {
-				String rootFilename = qitem.getRootFilename();
 				File resourceDirectory = qpoolFileStorage.getDirectory(qitem.getDirectory());
 				File itemFile = new File(resourceDirectory, qitem.getRootFilename());
-				String itemFilename = itemFile.getName();
-				ResolvedAssessmentItem resolvedAssessmentItem = qtiService.loadAndResolveAssessmentItem(itemFile.toURI(), resourceDirectory);
+				ResolvedAssessmentItem resolvedAssessmentItem = qtiService.loadAndResolveAssessmentItemForCopy(itemFile.toURI(), resourceDirectory);
+				AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
+				assessmentItem.setIdentifier(QTI21QuestionType.generateNewIdentifier(assessmentItem.getIdentifier()));
+				
+				//save the item in its own container
+				File container = new File(directory, qitem.getKey().toString());
+				container.mkdirs();
+				File newItemFile = new File(container, assessmentItem.getIdentifier() + ".xml");
+				String newItemFilename = container  + "/" + newItemFile.getName();
+				qtiService.persistAssessmentObject(newItemFile, assessmentItem);
 
-				//enrichScore(itemEl);
-				//collectResources(itemEl, container, materials);
-				FileUtils.bcopy(itemFile, new File(directory, rootFilename), "");
-				AssessmentTestFactory.appendAssessmentItem(section, itemFilename);
-				manifest.appendAssessmentItem(itemFilename);
-				ManifestMetadataBuilder metadata = manifest.getResourceBuilderByHref(itemFilename);
+				AssessmentTestFactory.appendAssessmentItem(section, newItemFilename);
+				manifest.appendAssessmentItem(newItemFilename);
+				ManifestMetadataBuilder metadata = manifest.getResourceBuilderByHref(newItemFilename);
 				enrichWithMetadata(qitem, resolvedAssessmentItem, metadata);
+				
+				Double maxScore = QtiNodesExtractor.extractMaxScore(assessmentItem);
+				if(maxScore != null) {
+					atomicMaxScore.add(maxScore.doubleValue());
+				}
+				
+				//write materials
+				AssessmentItemsAndResources materials = new AssessmentItemsAndResources();
+				ImportExportHelper.getMaterials(assessmentItem, itemFile, materials);
+				for(ItemMaterial material:materials.getMaterials()) {
+					String exportPath = material.getExportUri();
+					File originalFile = material.getFile();
+					File exportFile = new File(container, exportPath);
+					if(!exportFile.getParentFile().exists()) {
+						exportFile.getParentFile().mkdirs();
+					}
+					FileUtils.bcopy(originalFile, exportFile, "Copy material QTI 2.1");
+				}
+			}
+			
+			AssessmentTestBuilder assessmentTestBuilder = new AssessmentTestBuilder(assessmentTest);
+			double sumMaxScore = atomicMaxScore.sum();
+			if(sumMaxScore > 0.0d) {
+				assessmentTestBuilder.setMaxScore(sumMaxScore);
 			}
+			assessmentTest = assessmentTestBuilder.build();
 
 			try(FileOutputStream out = new FileOutputStream(new File(directory, assessmentTestFilename))) {
 				qtiSerializer.serializeJqtiObject(assessmentTest, out);	
@@ -233,7 +245,7 @@ public class QTI21ExportProcessor {
 			}
 
 	        manifest.write(new File(directory, "imsmanifest.xml"));
-		} catch (IOException | URISyntaxException e) {
+		} catch (Exception e) {
 			log.error("", e);
 		}
 	}
@@ -257,17 +269,33 @@ public class QTI21ExportProcessor {
 				File resourceDirectory = qpoolFileStorage.getDirectory(qitem.getDirectory());
 				File itemFile =  new File(resourceDirectory, qitem.getRootFilename());
 				String itemFilename = itemFile.getName();
+				String container = qitem.getKey().toString();
+				String containedFilename = container + "/" + itemFilename;
 
-				ResolvedAssessmentItem resolvedAssessmentItem = qtiService.loadAndResolveAssessmentItem(itemFile.toURI(), resourceDirectory);
-
-				//enrichScore(itemEl);
-				//collectResources(itemEl, container, materials);
-
-				ZipUtil.addFileToZip(itemFilename, itemFile, zout);
-				AssessmentTestFactory.appendAssessmentItem(section, itemFilename);
-				manifest.appendAssessmentItem(itemFilename);
-				ManifestMetadataBuilder metadata = manifest.getResourceBuilderByHref(itemFilename);
+				ResolvedAssessmentItem resolvedAssessmentItem = qtiService.loadAndResolveAssessmentItemForCopy(itemFile.toURI(), resourceDirectory);
+	
+				ZipUtil.addFileToZip(containedFilename, itemFile, zout);
+				AssessmentTestFactory.appendAssessmentItem(section, containedFilename);
+				manifest.appendAssessmentItem(containedFilename);
+				ManifestMetadataBuilder metadata = manifest.getResourceBuilderByHref(containedFilename);
 				enrichWithMetadata(qitem, resolvedAssessmentItem, metadata);
+				
+				//write materials
+				try {
+					Files.walkFileTree(resourceDirectory.toPath(), new SimpleFileVisitor<Path>() {
+						@Override
+						public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+							String filename = file.getFileName().toString();
+							if(!"imsmanifest.xml".equals(filename) && !filename.startsWith(".") && !itemFilename.equals(filename)) {
+								String relPath = resourceDirectory.toPath().relativize(file).toString();
+								ZipUtil.addFileToZip(container + "/" + relPath, file, zout);
+							}
+							return FileVisitResult.CONTINUE;
+						}
+					});
+				} catch (IOException e) {
+					log.error("", e);
+				}
 			}
 
 			zout.putNextEntry(new ZipEntry(assessmentTestFilename));
@@ -371,43 +399,4 @@ public class QTI21ExportProcessor {
 			metadata.setOpenOLATMetadataMasterIdentifier(qitem.getMasterIdentifier());
 		}
 	}
-
-	private static final class AssessmentItemsAndResources {
-		private final List<ResolvedAssessmentItem> itemEls = new ArrayList<>();
-		private final List<ItemMaterial> materials = new ArrayList<>();
-		
-		public List<ResolvedAssessmentItem> getAssessmentItems() {
-			return itemEls;
-		}
-		
-		public void addItemEl(ResolvedAssessmentItem el) {
-			itemEls.add(el);
-		}
-		
-		public List<ItemMaterial> getMaterials() {
-			return materials;
-		}
-		
-		public void addMaterial(ItemMaterial material) {
-			materials.add(material);
-		}
-	}
-	
-	private static final class ItemMaterial {
-		private final File file;
-		private final String exportUri;
-		
-		public ItemMaterial(File file, String exportUri) {
-			this.file = file;
-			this.exportUri = exportUri;
-		}
-		
-		public File getFile() {
-			return file;
-		}
-		
-		public String getExportUri() {
-			return exportUri;
-		}
-	}
 }
diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java b/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java
index fe5db51af56803e1d32d7ea9a104e2124f905449..7e9099b45571e930de0b31ce8b9b2f7e4b71b218 100644
--- a/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java
+++ b/src/main/java/org/olat/ims/qti21/pool/QTI21ImportProcessor.java
@@ -71,13 +71,10 @@ import org.olat.modules.qpool.model.QItemType;
 import org.olat.modules.qpool.model.QLicense;
 import org.olat.modules.qpool.model.QuestionItemImpl;
 
-import uk.ac.ed.ph.jqtiplus.node.content.xhtml.image.Img;
-import uk.ac.ed.ph.jqtiplus.node.content.xhtml.object.Object;
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.reading.AssessmentObjectXmlLoader;
 import uk.ac.ed.ph.jqtiplus.reading.QtiXmlReader;
 import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
-import uk.ac.ed.ph.jqtiplus.utils.QueryUtils;
 import uk.ac.ed.ph.jqtiplus.xmlutils.locators.FileResourceLocator;
 import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator;
 
@@ -193,7 +190,7 @@ public class QTI21ImportProcessor {
 			manifest.write(new File(itemStorage, "imsmanifest.xml"));
 			
 			//process material
-			List<String> materials = getMaterials(assessmentItem);
+			List<String> materials = ImportExportHelper.getMaterials(assessmentItem);
 			for(String material:materials) {
 				if(material.indexOf("://") < 0) {// material can be an external URL
 					Path materialFile = assessmentItemPath.getParent().resolve(material);
@@ -221,22 +218,6 @@ public class QTI21ImportProcessor {
 			log.error("", e);
 		}
 	}
-
-	protected List<String> getMaterials(AssessmentItem item) {
-		List<String> materials = new ArrayList<>();
-		QueryUtils.search(Img.class, item).forEach((img) -> {
-			if(img.getSrc() != null) {
-				materials.add(img.getSrc().toString());
-			}
-		});
-
-		QueryUtils.search(Object.class, item).forEach((object) -> {
-			if(StringHelper.containsNonWhitespace(object.getData())) {
-				materials.add(object.getData());
-			}
-		});
-		return materials;
-	}
 	
 	protected QuestionItemImpl processItem(AssessmentItem assessmentItem, String comment, String originalItemFilename,
 			String editor, String editorVersion, AssessmentItemMetadata metadata) {
diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java b/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java
index 0293c32288abc5ef38e8113f6cdc33735b93df57..992d62beb678688ea6d14463f099c13a5f53095c 100644
--- a/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java
+++ b/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java
@@ -28,8 +28,10 @@ import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import java.util.zip.ZipOutputStream;
@@ -444,7 +446,7 @@ public class QTI21QPoolServiceProvider implements QPoolSPI {
 		
 		//process material
 		File materialDirRoot = itemFile.getParentFile();
-		List<String> materials = processor.getMaterials(assessmentItem);
+		List<String> materials = ImportExportHelper.getMaterials(assessmentItem);
 		for(String material:materials) {
 			if(material.indexOf("://") < 0) {// material can be an external URL
 				try {
@@ -483,24 +485,36 @@ public class QTI21QPoolServiceProvider implements QPoolSPI {
 	}
 	
 	public void assembleTest(List<QuestionItemShort> items, Locale locale, ZipOutputStream zout) {
-		List<Long> itemKeys = new ArrayList<Long>();
-		for(QuestionItemShort item:items) {
-			itemKeys.add(item.getKey());
-		}
-
-		List<QuestionItemFull> fullItems = questionItemDao.loadByIds(itemKeys);
+		List<QuestionItemFull> fullItems = loadQuestionFullItems(items);
 		QTI21ExportProcessor processor = new QTI21ExportProcessor(qtiService, qpoolFileStorage, locale);
 		processor.assembleTest(fullItems, zout);	
 	}
 	
 	public void exportToEditorPackage(File exportDir, List<QuestionItemShort> items, Locale locale) {
-		List<Long> itemKeys = toKeys(items);
-		List<QuestionItemFull> fullItems = questionItemDao.loadByIds(itemKeys);
-
+		List<QuestionItemFull> fullItems = loadQuestionFullItems(items);
 		QTI21ExportProcessor processor = new QTI21ExportProcessor(qtiService, qpoolFileStorage, locale);
 		processor.assembleTest(fullItems, exportDir);
 	}
 	
+	private List<QuestionItemFull> loadQuestionFullItems(List<QuestionItemShort> items) {
+		List<Long> itemKeys = toKeys(items);
+		List<QuestionItemFull> fullItems = questionItemDao.loadByIds(itemKeys);
+		Map<Long, QuestionItemFull> fullItemMap = new HashMap<>();
+		for(QuestionItemFull fullItem:fullItems) {
+			fullItemMap.put(fullItem.getKey(), fullItem);
+		}
+		
+		//reorder the fullItems;
+		List<QuestionItemFull> reorderedFullItems = new ArrayList<>(fullItems.size());
+		for(QuestionItemShort item:items) {
+			QuestionItemFull itemFull = fullItemMap.get(item.getKey());
+			if(itemFull != null) {
+				reorderedFullItems.add(itemFull);
+			}
+		}
+		return reorderedFullItems;
+	}
+	
 	/**
 	 * Convert from QTI 1.2 to 2.1
 	 * 
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java
index 8a2e3224f2d12456b4f8c44ba1c5531737d2af04..78ca7ccec75981bbf27f482f389e1696715bf2f1 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentTestComposerController.java
@@ -1104,7 +1104,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 				qtiService.qtiSerializer().serializeJqtiObject(originalAssessmentItem, out);
 				
 				//change identifier and title
-				ResolvedAssessmentItem resolvedCopyItem = qtiService.loadAndResolveAssessmentItem(itemFile.toURI(), unzippedDirRoot);
+				ResolvedAssessmentItem resolvedCopyItem = qtiService.loadAndResolveAssessmentItemForCopy(itemFile.toURI(), unzippedDirRoot);
 				AssessmentItem copiedAssessmentItem = resolvedCopyItem.getRootNodeLookup().extractIfSuccessful();
 				copiedAssessmentItem.setIdentifier(IdentifierGenerator.newAsString(type.getPrefix()));
 				copiedAssessmentItem.setTitle(originalAssessmentItem.getTitle() + " (Copy)");