diff --git a/src/main/java/org/olat/ims/qti21/XmlUtilities.java b/src/main/java/org/olat/ims/qti21/XmlUtilities.java
new file mode 100644
index 0000000000000000000000000000000000000000..a61fc5384135944c31ab720f9e786e85be9dc31b
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/XmlUtilities.java
@@ -0,0 +1,50 @@
+/**
+ * <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;
+
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.XMLReader;
+
+/**
+ * 
+ * Initial date: 10.03.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public final class XmlUtilities {
+
+	private static final SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+	static {
+		parserFactory.setNamespaceAware(true);
+    	parserFactory.setValidating(false);
+	}
+
+	/**
+	 * @return XMLReader namespace aware but not validating.
+	 */
+    public static final XMLReader createNsAwareSaxReader() {
+        try {
+            return parserFactory.newSAXParser().getXMLReader();
+        } catch (final Exception e) {
+            throw new RuntimeException("Could not create NS-aware SAXParser with validating=false. Check deployment/runtime ClassPath", e);
+        }
+    }
+}
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 d97c259af677b5e1c05d228a105c63cbd3890e8e..18746c7be85592a9f79b28d27914cb8a2a7c349e 100644
--- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
+++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
@@ -69,7 +69,6 @@ import org.olat.ims.qti21.model.CandidateItemEventType;
 import org.olat.ims.qti21.model.CandidateTestEventType;
 import org.olat.ims.qti21.model.ResponseLegality;
 import org.olat.ims.qti21.model.jpa.CandidateEvent;
-import org.olat.ims.qti21.ui.rendering.XmlUtilities;
 import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryRef;
@@ -110,6 +109,7 @@ import uk.ac.ed.ph.jqtiplus.value.NumberValue;
 import uk.ac.ed.ph.jqtiplus.value.RecordValue;
 import uk.ac.ed.ph.jqtiplus.value.SingleValue;
 import uk.ac.ed.ph.jqtiplus.value.Value;
+import uk.ac.ed.ph.jqtiplus.xmlutils.XmlFactories;
 import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ClassPathResourceLocator;
 import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator;
 import uk.ac.ed.ph.jqtiplus.xmlutils.xslt.XsltSerializationOptions;
@@ -362,8 +362,8 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
     private Document loadStateDocument(AssessmentTestSession candidateSession) {
         File sessionFile = getTestSessionStateFile(candidateSession);
         if(sessionFile.exists()) {
-	        DocumentBuilder documentBuilder = XmlUtilities.createNsAwareDocumentBuilder();
 	        try {
+		        DocumentBuilder documentBuilder = XmlFactories.newDocumentBuilder();
 	            return documentBuilder.parse(sessionFile);
 	        } catch (final Exception e) {
 	            throw new OLATRuntimeException("Could not parse serailized state XML. This is an internal error as we currently don't expose this data to clients", e);
diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21EditorController.java b/src/main/java/org/olat/ims/qti21/pool/QTI21EditorController.java
index db32dc6dd560a767b8d9b184453b1bb8f7ba5129..626fe86b14add2f05cc286f63bdd70493512f456 100644
--- a/src/main/java/org/olat/ims/qti21/pool/QTI21EditorController.java
+++ b/src/main/java/org/olat/ims/qti21/pool/QTI21EditorController.java
@@ -29,6 +29,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.qti21.QTI21Service;
 import org.olat.ims.qti21.ui.editor.AssessmentItemEditorController;
 import org.olat.ims.qti21.ui.editor.events.AssessmentItemEvent;
@@ -65,6 +66,7 @@ public class QTI21EditorController extends BasicController implements QPoolItemE
 		mainVC = createVelocityContainer("pool_editor");
 		
 		File resourceDirectory = qpoolService.getRootDirectory(questionItem);
+		VFSContainer resourceContainer = qpoolService.getRootContainer(questionItem);
 		resourceFile = qpoolService.getRootFile(questionItem);
 		URI assessmentItemUri = resourceFile.toURI();
 		
@@ -72,7 +74,7 @@ public class QTI21EditorController extends BasicController implements QPoolItemE
 				.loadAndResolveAssessmentItem(assessmentItemUri, resourceDirectory);
 		
 		editorCtrl = new AssessmentItemEditorController(ureq, wControl,
-				resolvedAssessmentItem, resourceDirectory, resourceFile);
+				resolvedAssessmentItem, resourceDirectory, resourceContainer, resourceFile);
 		listenTo(editorCtrl);
 		mainVC.put("editor", editorCtrl.getInitialComponent());
 		
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponent.java
index d4bfb037a327579c77a3d1143b8e36df31aae05f..01573645b1c5d5f0f28bbdffaa674c9c2c58d12f 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponent.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponent.java
@@ -43,6 +43,11 @@ public class AssessmentItemComponent extends AssessmentObjectComponent {
 		this.qtiItem = qtiItem;
 	}
 	
+	@Override
+	public String relativePathTo(ResolvedAssessmentItem item) {
+		return "";
+	}
+	
 	public ResolvedAssessmentItem getResolvedAssessmentItem() {
 		return resolvedAssessmentItem;
 	}
@@ -51,6 +56,7 @@ public class AssessmentItemComponent extends AssessmentObjectComponent {
 		this.resolvedAssessmentItem = resolvedAssessmentItem;
 	}
 
+	@Override
 	public AssessmentItemFormItem getQtiItem() {
 		return qtiItem;
 	}
@@ -68,7 +74,6 @@ public class AssessmentItemComponent extends AssessmentObjectComponent {
 		this.itemSessionController = itemSessionController;
 	}
 
-
 	@Override
 	public AssessmentItemComponentRenderer getHTMLRendererSingleton() {
 		return RENDERER;
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java
index 0ffba5d9273c9a144ba2c1904d78e7f3cf59ce7b..ce0440a58042a2191c2eb1293c678a0b7b01088e 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentItemComponentRenderer.java
@@ -40,6 +40,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.item.template.declaration.TemplateDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.outcome.declaration.OutcomeDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.result.SessionStatus;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.running.ItemSessionController;
 import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
 import uk.ac.ed.ph.jqtiplus.types.Identifier;
@@ -162,19 +163,20 @@ public class AssessmentItemComponentRenderer extends AssessmentObjectComponentRe
 			URLBuilder ubu, Translator translator) {
 		
 		final AssessmentItem assessmentItem = component.getAssessmentItem();
+		final ResolvedAssessmentItem resolvedAssessmentItem = component.getResolvedAssessmentItem();
 
 		//title + status
 		sb.append("<h1 class='itemTitle'>");
 		renderItemStatus(renderer, sb, itemSessionState, translator);
-		sb.append(assessmentItem.getTitle()).append("</h1>");
-		sb.append("<div id='itemBody'>");
+		sb.append(assessmentItem.getTitle()).append("</h1>")
+		  .append("<div id='itemBody'>");
 		
 		//TODO prompt
 	
 
 		//render itemBody
 		assessmentItem.getItemBody().getBlocks().forEach((block)
-				-> renderBlock(renderer, sb, component, assessmentItem, itemSessionState, block, ubu, translator));
+				-> renderBlock(renderer, sb, component, resolvedAssessmentItem, itemSessionState, block, ubu, translator));
 
 		//comment
 		renderComment(renderer, sb, component, itemSessionState, translator);
@@ -190,7 +192,7 @@ public class AssessmentItemComponentRenderer extends AssessmentObjectComponentRe
 
 		// Display active modal feedback (only after responseProcessing)
 		if(itemSessionState.getSessionStatus() == SessionStatus.FINAL) {
-			renderTestItemModalFeedback(renderer, sb, component, assessmentItem, itemSessionState, ubu, translator);
+			renderTestItemModalFeedback(renderer, sb, component, resolvedAssessmentItem, itemSessionState, ubu, translator);
 		}
 	}
     
@@ -203,8 +205,8 @@ public class AssessmentItemComponentRenderer extends AssessmentObjectComponentRe
 	}
 	
 	@Override
-	protected void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component, AssessmentItem assessmentItem, ItemSessionState itemSessionState,
-			PrintedVariable printedVar) {
+	protected void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem,
+			ItemSessionState itemSessionState, PrintedVariable printedVar) {
 
 		Identifier identifier = printedVar.getIdentifier();
 		Value templateValue = itemSessionState.getTemplateValues().get(identifier);
@@ -212,10 +214,12 @@ public class AssessmentItemComponentRenderer extends AssessmentObjectComponentRe
 		
 		sb.append("<span class='printedVariable'>");
 		if(outcomeValue != null) {
-			OutcomeDeclaration outcomeDeclaration = assessmentItem.getOutcomeDeclaration(identifier);
+			OutcomeDeclaration outcomeDeclaration = resolvedAssessmentItem.getRootNodeLookup()
+					.extractIfSuccessful().getOutcomeDeclaration(identifier);
 			renderPrintedVariable(renderer, sb, printedVar, outcomeDeclaration, outcomeValue);
 		} else if(templateValue != null) {
-			TemplateDeclaration templateDeclaration = assessmentItem.getTemplateDeclaration(identifier);
+			TemplateDeclaration templateDeclaration = resolvedAssessmentItem.getRootNodeLookup()
+					.extractIfSuccessful().getTemplateDeclaration(identifier);
 			renderPrintedVariable(renderer, sb, printedVar, templateDeclaration, templateValue);
 		} else {
 			sb.append("(variable ").append(identifier.toString()).append(" was not found)");
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java
index ce4d0b30f02600a05446c2ddebc880174af54b76..782b20a3d145aae06986ff65ed1f615b44b33533 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java
@@ -36,6 +36,7 @@ import org.olat.ims.qti21.ui.CandidateSessionContext;
 import uk.ac.ed.ph.jqtiplus.node.content.variable.FeedbackElement;
 import uk.ac.ed.ph.jqtiplus.node.item.ModalFeedback;
 import uk.ac.ed.ph.jqtiplus.node.test.VisibilityMode;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
 import uk.ac.ed.ph.jqtiplus.types.Identifier;
 import uk.ac.ed.ph.jqtiplus.value.Value;
@@ -78,6 +79,8 @@ public abstract class AssessmentObjectComponent extends AbstractComponent implem
 		this.assessmentObjectUri = assessmentObjectUri;
 	}
 	
+	public abstract String relativePathTo(ResolvedAssessmentItem resolvedAssessmentItem);
+	
 	public ResourceLocator getResourceLocator() {
 		return resourceLocator;
 	}
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java
index 9dc2c59d57de16c5b8236f418b6865a6bd53fdf1..5e9b225fdfd9a57e953cb067d9923a564dc52d91 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponentRenderer.java
@@ -81,7 +81,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.ims.qti21.QTI21Service;
-import org.olat.ims.qti21.ui.rendering.XmlUtilities;
+import org.olat.ims.qti21.XmlUtilities;
 import org.xml.sax.InputSource;
 import org.xml.sax.XMLReader;
 
@@ -138,6 +138,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.shared.VariableDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.test.NavigationMode;
 import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.running.TestSessionController;
 import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
 import uk.ac.ed.ph.jqtiplus.types.Identifier;
@@ -193,8 +194,9 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	protected void renderTestItemModalFeedback(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, URLBuilder ubu, Translator translator) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, URLBuilder ubu, Translator translator) {
 		List<ModalFeedback> modalFeedbacks = new ArrayList<>();
+		AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
 		for(ModalFeedback modalFeedback:assessmentItem.getModalFeedbacks()) {
 			if(component.isFeedback(modalFeedback, itemSessionState)) {
 				modalFeedbacks.add(modalFeedback);
@@ -212,7 +214,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 				}
 				
 				modalFeedback.getFlowStatics().forEach((flow)
-					-> renderFlow(renderer, sb, component, assessmentItem, itemSessionState, flow, ubu, translator));
+					-> renderFlow(renderer, sb, component, resolvedAssessmentItem, itemSessionState, flow, ubu, translator));
 
 				sb.append("</div>");
 			}
@@ -222,21 +224,21 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	public void renderFlow(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, Flow flow, URLBuilder ubu, Translator translator) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, Flow flow, URLBuilder ubu, Translator translator) {
 		
 		if(flow instanceof Block) {
-			renderBlock(renderer, sb, component, assessmentItem, itemSessionState, (Block)flow, ubu, translator);
+			renderBlock(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (Block)flow, ubu, translator);
 		} else if(flow instanceof Inline) {
-			renderInline(renderer, sb, component, assessmentItem, itemSessionState, (Inline)flow, ubu, translator);
+			renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (Inline)flow, ubu, translator);
 		} else {
 			log.error("What is it for a flow static object: " + flow);
 		}
 	}
 	
 	public void renderTextOrVariable(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, TextOrVariable textOrVariable) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, TextOrVariable textOrVariable) {
 		if(textOrVariable instanceof PrintedVariable) {
-			renderPrintedVariable(renderer, sb, component, assessmentItem, itemSessionState, (PrintedVariable)textOrVariable);
+			renderPrintedVariable(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (PrintedVariable)textOrVariable);
 		} else if(textOrVariable instanceof TextRun) {
 			sb.append(((TextRun)textOrVariable).getTextContent());
 		} else {
@@ -245,7 +247,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	public void renderBlock(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, Block block, URLBuilder ubu, Translator translator) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, Block block, URLBuilder ubu, Translator translator) {
 		
 		switch(block.getQtiClassName()) {
 			case AssociateInteraction.QTI_CLASS_NAME:
@@ -265,20 +267,20 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 			case PositionObjectInteraction.QTI_CLASS_NAME:
 			case SliderInteraction.QTI_CLASS_NAME:
 			case UploadInteraction.QTI_CLASS_NAME: {
-				renderInteraction(renderer, sb, (FlowInteraction)block, assessmentItem, itemSessionState, component, ubu, translator);
+				renderInteraction(renderer, sb, (FlowInteraction)block, resolvedAssessmentItem, itemSessionState, component, ubu, translator);
 				break;
 			}
 			case CustomInteraction.QTI_CLASS_NAME: {
-				renderCustomInteraction(renderer, sb, (CustomInteraction<?>)block, assessmentItem, itemSessionState, component, ubu, translator);
+				renderCustomInteraction(renderer, sb, (CustomInteraction<?>)block, resolvedAssessmentItem, itemSessionState, component, ubu, translator);
 				break;
 			}
 			case PositionObjectStage.QTI_CLASS_NAME: {
-				renderPositionObjectStage(renderer, sb, (PositionObjectStage)block, assessmentItem, itemSessionState, component, ubu, translator);
+				renderPositionObjectStage(renderer, sb, (PositionObjectStage)block, resolvedAssessmentItem, itemSessionState, component, ubu, translator);
 				break;
 			}
 			case TemplateBlock.QTI_CLASS_NAME: break;//never rendered
 			case InfoControl.QTI_CLASS_NAME: {
-				renderInfoControl(renderer, sb, component, assessmentItem, itemSessionState, (InfoControl)block, ubu, translator);
+				renderInfoControl(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (InfoControl)block, ubu, translator);
 				break;
 			}
 			case FeedbackBlock.QTI_CLASS_NAME: {
@@ -286,40 +288,40 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 				if(component.isFeedback(feedbackBlock, itemSessionState)) {
 					sb.append("<div class='o_info feedbackBlock '").append(getAtClass(feedbackBlock)).append(">");
 					feedbackBlock.getBlocks().forEach((child)
-							-> renderBlock(renderer, sb, component, assessmentItem, itemSessionState, child, ubu, translator));
+							-> renderBlock(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator));
 					sb.append("</div>");
 				}
 				break;
 			}
 			case RubricBlock.QTI_CLASS_NAME: break; //never rendered automatically
 			case Math.QTI_CLASS_NAME: {
-				renderMath(renderer, sb, component, assessmentItem, itemSessionState, (Math)block);
+				renderMath(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (Math)block);
 				break;
 			}
 			case Div.QTI_CLASS_NAME:
-				renderStartHtmlTag(sb, component, block, null);
+				renderStartHtmlTag(sb, component, resolvedAssessmentItem, block, null);
 				((Div)block).getFlows().forEach((flow)
-						-> renderFlow(renderer, sb, component, assessmentItem, itemSessionState, flow, ubu, translator));
+						-> renderFlow(renderer, sb, component, resolvedAssessmentItem, itemSessionState, flow, ubu, translator));
 				renderEndTag(sb, block);
 				break;
 			default: {
-				renderStartHtmlTag(sb, component, block, null);
+				renderStartHtmlTag(sb, component, resolvedAssessmentItem, block, null);
 				if(block instanceof AtomicBlock) {
 					AtomicBlock atomicBlock = (AtomicBlock)block;
 					atomicBlock.getInlines().forEach((child)
-							-> renderInline(renderer, sb, component, assessmentItem, itemSessionState, child, ubu, translator));
+							-> renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator));
 					
 				} else if(block instanceof SimpleBlock) {
 					SimpleBlock simpleBlock = (SimpleBlock)block;
 					simpleBlock.getBlocks().forEach((child)
-							-> renderBlock(renderer, sb, component, assessmentItem, itemSessionState, child, ubu, translator));
+							-> renderBlock(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator));
 				}
 				renderEndTag(sb, block);
 			}
 		}
 	}
 	
-	public void renderInline(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component, AssessmentItem assessmentItem,
+	public void renderInline(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem,
 			ItemSessionState itemSessionState, Inline inline, URLBuilder ubu, Translator translator) {
 		
 		switch(inline.getQtiClassName()) {
@@ -329,11 +331,11 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 			}
 			case InlineChoiceInteraction.QTI_CLASS_NAME:
 			case TextEntryInteraction.QTI_CLASS_NAME: {
-				renderInteraction(renderer, sb, (FlowInteraction)inline, assessmentItem, itemSessionState, component, ubu, translator);
+				renderInteraction(renderer, sb, (FlowInteraction)inline, resolvedAssessmentItem, itemSessionState, component, ubu, translator);
 				break;
 			}
 			case Hottext.QTI_CLASS_NAME: {
-				renderHottext(renderer, sb, assessmentItem, itemSessionState, (Hottext)inline, component, ubu, translator);
+				renderHottext(renderer, sb, resolvedAssessmentItem, itemSessionState, (Hottext)inline, component, ubu, translator);
 				break;
 			}
 			case Gap.QTI_CLASS_NAME: {
@@ -341,7 +343,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 				break;
 			}
 			case PrintedVariable.QTI_CLASS_NAME: {
-				renderPrintedVariable(renderer, sb, component, assessmentItem, itemSessionState, (PrintedVariable)inline);
+				renderPrintedVariable(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (PrintedVariable)inline);
 				break;
 			}
 			case TemplateInline.QTI_CLASS_NAME: break; //not part of the item body
@@ -350,7 +352,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 				if(component.isFeedback(feedbackInline, itemSessionState)) {
 					sb.append("<span class='feedbackInline ").append(getAtClass(feedbackInline)).append("'>");
 					feedbackInline.getInlines().forEach((child)
-							-> renderInline(renderer, sb, component, assessmentItem, itemSessionState, child, ubu, translator));
+							-> renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator));
 					sb.append("</span>");
 				}
 				break;
@@ -360,11 +362,11 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 				break;
 			}
 			case Math.QTI_CLASS_NAME: {
-				renderMath(renderer, sb, component, assessmentItem, itemSessionState, (Math)inline);
+				renderMath(renderer, sb, component, resolvedAssessmentItem, itemSessionState, (Math)inline);
 				break;
 			}
 			case Img.QTI_CLASS_NAME: {
-				renderHtmlTag(sb, component, inline, null);
+				renderHtmlTag(sb, component, resolvedAssessmentItem, inline, null);
 				break;
 			}
 			case Br.QTI_CLASS_NAME: {
@@ -372,11 +374,11 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 				break;
 			}
 			default: {
-				renderStartHtmlTag(sb, component, inline, null);
+				renderStartHtmlTag(sb, component, resolvedAssessmentItem, inline, null);
 				if(inline instanceof SimpleInline) {
 					SimpleInline simpleInline = (SimpleInline)inline;
 					simpleInline.getInlines().forEach((child)
-							-> renderInline(renderer, sb, component, assessmentItem, itemSessionState, child, ubu, translator));
+							-> renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, child, ubu, translator));
 				}
 				renderEndTag(sb, inline);
 			}
@@ -384,20 +386,20 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	protected final void renderInfoControl(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, InfoControl infoControl, URLBuilder ubu, Translator translator) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, InfoControl infoControl, URLBuilder ubu, Translator translator) {
 		sb.append("<div class=\"infoControl\">")
 		  .append("<button type='button' onclick=\"return QtiWorksRendering.showInfoControlContent(this)\" class='btn btn-default'>")
 		  .append("<span>").append(infoControl.getTitle()).append("</span></button>")
 		  .append("<div class='infoControlContent o_info'>");
 		infoControl.getChildren().forEach((flow)
-				-> renderFlow(renderer, sb, component, assessmentItem, itemSessionState, flow, ubu, translator));
+				-> renderFlow(renderer, sb, component, resolvedAssessmentItem, itemSessionState, flow, ubu, translator));
 		sb.append("</div></div>");
 	}
 	
-	protected final void renderHtmlTag(StringOutput sb, AssessmentObjectComponent component, QtiNode node, String cssClass) {
+	protected final void renderHtmlTag(StringOutput sb, AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, QtiNode node, String cssClass) {
 		sb.append("<").append(node.getQtiClassName());
 		for(Attribute<?> attribute:node.getAttributes()) {
-			String value = getHtmlAttributeValue(component, attribute);
+			String value = getHtmlAttributeValue(component, resolvedAssessmentItem, attribute);
 			if(StringHelper.containsNonWhitespace(value)) {
 				String name = attribute.getLocalName();
 				sb.append(" ").append(name).append("=\"").append(value);
@@ -410,10 +412,10 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 		sb.append(" />");
 	}
 	
-	protected final void renderStartHtmlTag(StringOutput sb, AssessmentObjectComponent component, QtiNode node, String cssClass) {
+	protected final void renderStartHtmlTag(StringOutput sb, AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, QtiNode node, String cssClass) {
 		sb.append("<").append(node.getQtiClassName());
 		for(Attribute<?> attribute:node.getAttributes()) {
-			String value = getHtmlAttributeValue(component, attribute);
+			String value = getHtmlAttributeValue(component, resolvedAssessmentItem, attribute);
 			if(StringHelper.containsNonWhitespace(value)) {
 				String name = attribute.getLocalName();
 				sb.append(" ").append(name).append("=\"").append(value);
@@ -496,12 +498,12 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	private void renderPositionObjectStage(AssessmentRenderer renderer, StringOutput sb, PositionObjectStage positionObjectStage,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
 			URLBuilder ubu, Translator translator) {
 		Context ctx = new VelocityContext();
 		ctx.put("positionObjectStage", positionObjectStage);
 		String page = getInteractionTemplate(positionObjectStage);
-		renderVelocity(renderer, sb, positionObjectStage, ctx, page, assessmentItem, itemSessionState, component, ubu, translator);
+		renderVelocity(renderer, sb, positionObjectStage, ctx, page, resolvedAssessmentItem, itemSessionState, component, ubu, translator);
 	}
 	
 	/**
@@ -516,7 +518,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	 * @param translator
 	 */
 	private void renderCustomInteraction(AssessmentRenderer renderer, StringOutput sb, CustomInteraction<?> interaction,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
 			URLBuilder ubu, Translator translator) {
 		Context ctx = new VelocityContext();
 		ctx.put("interaction", interaction);
@@ -527,7 +529,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 		} else {
 			page = velocity_root + "/unsupportedCustomInteraction.html";
 		}
-		renderVelocity(renderer, sb, interaction, ctx, page, assessmentItem, itemSessionState, component, ubu, translator);
+		renderVelocity(renderer, sb, interaction, ctx, page, resolvedAssessmentItem, itemSessionState, component, ubu, translator);
 	}
 	
 	/**
@@ -542,27 +544,28 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	 * @param translator
 	 */
 	private void renderInteraction(AssessmentRenderer renderer, StringOutput sb, FlowInteraction interaction,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
 			URLBuilder ubu, Translator translator) {
 		Context ctx = new VelocityContext();
 		ctx.put("interaction", interaction);
 		String page = getInteractionTemplate(interaction);
-		renderVelocity(renderer, sb, interaction, ctx, page, assessmentItem, itemSessionState, component, ubu, translator);
+		renderVelocity(renderer, sb, interaction, ctx, page, resolvedAssessmentItem, itemSessionState, component, ubu, translator);
 	}
 		
 	private void renderVelocity(AssessmentRenderer renderer, StringOutput sb, QtiNode interaction, Context ctx, String page,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, AssessmentObjectComponent component,
 			URLBuilder ubu, Translator translator) {
 
 		ctx.put("localName", interaction.getQtiClassName());
-		ctx.put("assessmentItem", assessmentItem);
+		ctx.put("assessmentItem", resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful());
 		ctx.put("itemSessionState", itemSessionState);
 		ctx.put("isItemSessionOpen", component.isItemSessionOpen(itemSessionState, renderer.isSolutionMode()));
 		ctx.put("isItemSessionEnded", component.isItemSessionEnded(itemSessionState, renderer.isSolutionMode()));
 
 		Renderer fr = Renderer.getInstance(component, translator, ubu, new RenderResult(), renderer.getGlobalSettings());
 		AssessmentRenderer fHints = renderer.newHints(fr);
-		AssessmentObjectVelocityRenderDecorator vrdec = new AssessmentObjectVelocityRenderDecorator(fHints, sb, component, assessmentItem, itemSessionState, ubu, translator);			
+		AssessmentObjectVelocityRenderDecorator vrdec
+			= new AssessmentObjectVelocityRenderDecorator(fHints, sb, component, resolvedAssessmentItem, itemSessionState, ubu, translator);			
 		ctx.put("r", vrdec);
 		VelocityHelper vh = VelocityHelper.getInstance();
 		vh.mergeContent(page, ctx, sb, null);
@@ -640,7 +643,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	    </xsl:if>
 	  </xsl:template>
 	 */
-	private void renderHottext(AssessmentRenderer renderer, StringOutput sb, AssessmentItem assessmentItem, ItemSessionState itemSessionState, Hottext hottext,
+	private void renderHottext(AssessmentRenderer renderer, StringOutput sb, ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, Hottext hottext,
 			AssessmentObjectComponent component, URLBuilder ubu, Translator translator) {
 		if(!isVisible(hottext, itemSessionState)) return;
 		
@@ -664,13 +667,14 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 			if(component.isItemSessionEnded(itemSessionState, renderer.isSolutionMode())) {
 				sb.append(" disabled");
 			}
+			AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
 			Value responseValue = getResponseValue(assessmentItem, itemSessionState, interaction.getResponseIdentifier(), renderer.isSolutionMode());
 			if(valueContains(responseValue, hottext.getIdentifier())) {
 				sb.append(" checked");
 			}
 			sb.append(" />");
 			hottext.getInlineStatics().forEach((inline)
-					-> renderInline(renderer, sb, component, assessmentItem, itemSessionState, inline, ubu, translator));
+					-> renderInline(renderer, sb, component, resolvedAssessmentItem, itemSessionState, inline, ubu, translator));
 			sb.append("</span>");
 		}
 	}
@@ -797,7 +801,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	protected abstract void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb,
-			AssessmentObjectComponent component, AssessmentItem assessmentItem, ItemSessionState itemSessionState,
+			AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState,
 			PrintedVariable printedVar);
 	
 	/**
@@ -875,13 +879,13 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	protected void renderMath(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, Math math) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, Math math) {
 		
 		renderer.setMathXsltDisabled(true);
 		StringOutput mathOutput = StringOutputPool.allocStringBuilder(2048);
 		mathOutput.append("<math xmlns=\"http://www.w3.org/1998/Math/MathML\">");
 		math.getContent().forEach((foreignElement)
-				-> renderMath(renderer, mathOutput, component, assessmentItem, itemSessionState, foreignElement));
+				-> renderMath(renderer, mathOutput, component, resolvedAssessmentItem, itemSessionState, foreignElement));
 		mathOutput.append("</math>");
 		String enrichedMathML = StringOutputPool.freePop(mathOutput);
 		renderer.setMathXsltDisabled(false);
@@ -889,19 +893,20 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 	}
 	
 	protected void renderMath(AssessmentRenderer renderer, StringOutput out, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, QtiNode mathElement) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, QtiNode mathElement) {
 		if(mathElement instanceof ForeignElement) {
 			ForeignElement fElement = (ForeignElement)mathElement;
 			boolean mi = fElement.getQtiClassName().equals("mi");
 			boolean ci = fElement.getQtiClassName().equals("ci");
 			
 			if(ci || mi) {
+				AssessmentItem assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
+				
 				String text = contentAsString(fElement);
 				Identifier identifier = Identifier.assumedLegal(text);
 				Value templateValue = getTemplateValue(itemSessionState, text);
 				Value outcomeValue = getOutcomeValue(itemSessionState, text);
 				Value responseValue = getResponseValue(assessmentItem, itemSessionState, identifier, renderer.isSolutionMode());
-
 				if(templateValue != null && isTemplateDeclarationAMathVariable(assessmentItem, text)) {
 					if(ci) {
 						substituteCi(out, templateValue);
@@ -921,15 +926,15 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 						substituteMi(out, responseValue);
 					}
 				} else {
-					renderStartHtmlTag(out, component, fElement, null);
+					renderStartHtmlTag(out, component, resolvedAssessmentItem, fElement, null);
 					fElement.getChildren().forEach((child)
-							-> renderMath(renderer, out, component, assessmentItem, itemSessionState, child));
+							-> renderMath(renderer, out, component, resolvedAssessmentItem, itemSessionState, child));
 					renderEndTag(out, fElement);
 				}
 			} else {
-				renderStartHtmlTag(out, component, fElement, null);
+				renderStartHtmlTag(out, component, resolvedAssessmentItem, fElement, null);
 				fElement.getChildren().forEach((child)
-						-> renderMath(renderer, out, component, assessmentItem, itemSessionState, child));
+						-> renderMath(renderer, out, component, resolvedAssessmentItem, itemSessionState, child));
 				renderEndTag(out, fElement);
 			}
 		} else if(mathElement instanceof TextRun) {
@@ -1061,7 +1066,7 @@ public abstract class AssessmentObjectComponentRenderer extends DefaultComponent
 
         try {
             mathmlTransformerHandler.setResult(new StreamResult(sb));
-            final XMLReader xmlReader = XmlUtilities.createNsAwareSaxReader(false);
+            final XMLReader xmlReader = XmlUtilities.createNsAwareSaxReader();
             xmlReader.setContentHandler(mathmlTransformerHandler);
         	
             Reader mathStream = new StringReader(mathmlAsString);
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java
index f3591f131301e4a81966cde59c49520a1c36e607..dd49cb9075e6ed190a13830fc421530ad336049c 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java
@@ -67,6 +67,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.content.Gap;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.graphic.AssociableHotspot;
 import uk.ac.ed.ph.jqtiplus.node.item.interaction.graphic.HotspotChoice;
 import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
 import uk.ac.ed.ph.jqtiplus.types.Identifier;
 import uk.ac.ed.ph.jqtiplus.types.ResponseData;
@@ -96,20 +97,22 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor
 	
 	private final AssessmentItem assessmentItem;
 	private final ItemSessionState itemSessionState;
+	private final ResolvedAssessmentItem resolvedAssessmentItem;
 	
 	private final AssessmentObjectComponent avc;
 	
 	
 	public AssessmentObjectVelocityRenderDecorator(AssessmentRenderer renderer, StringOutput target, AssessmentObjectComponent vc,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, URLBuilder ubu, Translator translator) {
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, URLBuilder ubu, Translator translator) {
 		super(renderer.getRenderer(), vc, target);
 		this.avc = vc;
 		this.ubu = ubu;
 		this.target = target;
 		this.renderer = renderer;
 		this.translator = translator;
-		this.assessmentItem = assessmentItem;
 		this.itemSessionState = itemSessionState;
+		this.resolvedAssessmentItem = resolvedAssessmentItem;
+		this.assessmentItem = resolvedAssessmentItem.getRootNodeLookup().extractIfSuccessful();
 	}
 
 	public boolean isSolutionMode() {
@@ -126,11 +129,11 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor
 	}
 	
 	public String convertLink(String uri) {
-		return AssessmentRenderFunctions.convertLink(avc, uri);
+		return AssessmentRenderFunctions.convertLink(avc, resolvedAssessmentItem, uri);
 	}
 	
 	public String convertLinkFull(String uri) {
-		return AssessmentRenderFunctions.convertLink(avc, uri);
+		return AssessmentRenderFunctions.convertLink(avc, resolvedAssessmentItem, uri);
 	}
 	
 	public boolean isNullValue(Value value) {
@@ -477,14 +480,14 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor
 	public String renderPrompt(Prompt prompt) {
 		if(prompt != null) {
 			prompt.getInlineStatics().forEach((inline)
-					->	avc.getHTMLRendererSingleton().renderInline(renderer, target, avc, assessmentItem, itemSessionState, inline, ubu, translator));
+					->	avc.getHTMLRendererSingleton().renderInline(renderer, target, avc, resolvedAssessmentItem, itemSessionState, inline, ubu, translator));
 		}
 		return "";
 	}
 	
 	public String renderBlock(Block block) {
 		if(block != null) {
-			avc.getHTMLRendererSingleton().renderBlock(renderer, target, avc, assessmentItem, itemSessionState, block, ubu, translator);
+			avc.getHTMLRendererSingleton().renderBlock(renderer, target, avc, resolvedAssessmentItem, itemSessionState, block, ubu, translator);
 		}
 		return "";
 	}
@@ -492,7 +495,7 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor
 	public String renderBlockStatics(List<BlockStatic> blockStaticList) {
 		if(blockStaticList != null && blockStaticList.size() > 0) {
 			blockStaticList.forEach((block)
-					-> avc.getHTMLRendererSingleton().renderBlock(renderer, target, avc, assessmentItem, itemSessionState, block, ubu, translator));
+					-> avc.getHTMLRendererSingleton().renderBlock(renderer, target, avc, resolvedAssessmentItem, itemSessionState, block, ubu, translator));
 		}
 		return "";
 	}
@@ -500,7 +503,7 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor
 	public String renderFlowStatics(List<FlowStatic> flowStaticList) {
 		if(flowStaticList != null && flowStaticList.size() > 0) {
 			flowStaticList.forEach((flow)
-					-> avc.getHTMLRendererSingleton().renderFlow(renderer, target, avc, assessmentItem, itemSessionState, flow, ubu, translator));
+					-> avc.getHTMLRendererSingleton().renderFlow(renderer, target, avc, resolvedAssessmentItem, itemSessionState, flow, ubu, translator));
 		}
 		return "";
 	}
@@ -508,14 +511,14 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor
 	public String renderTextOrVariables(List<TextOrVariable> textOrVariables) {
 		if(textOrVariables != null && textOrVariables.size() > 0) {
 			textOrVariables.forEach((textOrVariable)
-					-> avc.getHTMLRendererSingleton().renderTextOrVariable(renderer, target, avc, assessmentItem, itemSessionState, textOrVariable));
+					-> avc.getHTMLRendererSingleton().renderTextOrVariable(renderer, target, avc, resolvedAssessmentItem, itemSessionState, textOrVariable));
 		}
 		return "";
 	}
 	
 	public String renderFlow(Flow flow) {
 		if(flow != null) {
-			avc.getHTMLRendererSingleton().renderFlow(renderer, target, avc, assessmentItem, itemSessionState, flow, ubu, translator);
+			avc.getHTMLRendererSingleton().renderFlow(renderer, target, avc, resolvedAssessmentItem, itemSessionState, flow, ubu, translator);
 		}
 		return "";
 	}
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java
index dc60e93ac12248ad951c0a734b0d14967edf52d3..cea6bf8d3fb0cc5a83460b71707407683f9e45dd 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java
@@ -40,6 +40,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.Choice;
 import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.item.template.declaration.TemplateDeclaration;
 import uk.ac.ed.ph.jqtiplus.node.test.VisibilityMode;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
 import uk.ac.ed.ph.jqtiplus.types.Identifier;
 import uk.ac.ed.ph.jqtiplus.types.ResponseData;
@@ -517,7 +518,7 @@ public class AssessmentRenderFunctions {
 	 * @return
 	 */
 	@SuppressWarnings({ "rawtypes" })
-	public static final String getHtmlAttributeValue(AssessmentObjectComponent component, Attribute attribute) {
+	public static final String getHtmlAttributeValue(AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, Attribute attribute) {
 		String value;
 		String name = attribute.getLocalName();
 		switch(name) {
@@ -530,7 +531,7 @@ public class AssessmentRenderFunctions {
 			case "href":
 			case "src":
 				String uri = getDomAttributeValue(attribute);
-				value = convertLink(component, uri);
+				value = convertLink(component, resolvedAssessmentItem, uri);
 				break;
 			default:
 				value = null;
@@ -564,11 +565,14 @@ public class AssessmentRenderFunctions {
     </xsl:choose>
   </xsl:function>
 	 */
-	public static final String convertLink(AssessmentObjectComponent component, String uri) {
+	public static final String convertLink(AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, String uri) {
 		if(uri.startsWith("http:") || uri.startsWith("https:") || uri.startsWith("mailto:")) {
 			return uri;
 		}
-		uri = component.getMapperUri() + "/file?href=" + uri;
+		
+		String relativePath = component.relativePathTo(resolvedAssessmentItem);
+		uri = component.getMapperUri() + "/file?href=" + relativePath + uri;
+		System.out.println("Rewrite: " + uri);
 		return uri;
 	}
 
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponent.java
index 76104c2ba4ee525a2003f41d32cca803dacc0f0e..7c6cff210041dea8aa82f55c8f1d46f6fce76d54 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponent.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponent.java
@@ -19,6 +19,9 @@
  */
 package org.olat.ims.qti21.ui.components;
 
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
 import java.util.List;
 
 import org.olat.ims.qti21.ui.components.AssessmentObjectComponentRenderer.RenderingRequest;
@@ -28,6 +31,7 @@ import uk.ac.ed.ph.jqtiplus.node.result.SessionStatus;
 import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
 import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
 import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest;
 import uk.ac.ed.ph.jqtiplus.running.TestSessionController;
 import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
@@ -102,6 +106,22 @@ public class AssessmentTestComponent extends AssessmentObjectComponent  {
 	public void setResolvedAssessmentTest(ResolvedAssessmentTest resolvedAssessmentTest) {
 		this.resolvedAssessmentTest = resolvedAssessmentTest;
 	}
+	
+	@Override
+	public String relativePathTo(ResolvedAssessmentItem resolvedAssessmentItem) {
+		URI itemUri = resolvedAssessmentItem.getItemLookup().getSystemId();
+		File itemFile = new File(itemUri);
+		URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId();
+		File testFile = new File(testUri);
+		Path relativePath = testFile.toPath().getParent().relativize(itemFile.toPath().getParent());
+		String relativePathString = relativePath.toString();
+		if(relativePathString.isEmpty()) {
+			return relativePathString;
+		} else if(relativePathString.endsWith("/")) {
+			return relativePathString;
+		}
+		return relativePathString.concat("/");
+	}
 
 	public AssessmentTest getAssessmentTest() {
 		return getResolvedAssessmentTest().getRootNodeLookup().extractIfSuccessful();
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java
index 0b970f4f6acf693bf8f6b6e3a46abbbe10ccbbf9..ade51a4e1e0b35e16b84810298ac6bc736519847 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestComponentRenderer.java
@@ -344,7 +344,7 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 
 		//render itemBody
 		assessmentItem.getItemBody().getBlocks().forEach((block)
-				-> renderBlock(renderer, sb, component, assessmentItem, itemSessionState, block, ubu, translator));
+				-> renderBlock(renderer, sb, component, resolvedAssessmentItem, itemSessionState, block, ubu, translator));
 
 		//comment
 		renderComment(renderer, sb, component, itemSessionState, translator);
@@ -359,12 +359,12 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 
 		// Display active modal feedback (only after responseProcessing)
 		if(component.isItemFeedbackAllowed(itemNode, assessmentItem, options)) {
-			renderTestItemModalFeedback(renderer, sb, component, assessmentItem, itemSessionState, ubu, translator);
+			renderTestItemModalFeedback(renderer, sb, component, resolvedAssessmentItem, itemSessionState, ubu, translator);
 		}
 	}
 	
 	@Override
-	protected void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component, AssessmentItem assessmentItem,
+	protected void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb, AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem,
 			ItemSessionState itemSessionState, PrintedVariable printedVar) {
 		
 		AssessmentTestComponent testCmp = (AssessmentTestComponent)component;
@@ -380,10 +380,12 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 			Value templateValue = itemSessionState.getTemplateValues().get(identifier);
 			Value outcomeValue = itemSessionState.getOutcomeValues().get(identifier);
 			if(outcomeValue != null) {
-				OutcomeDeclaration outcomeDeclaration = assessmentItem.getOutcomeDeclaration(identifier);
+				OutcomeDeclaration outcomeDeclaration = resolvedAssessmentItem.getRootNodeLookup()
+						.extractIfSuccessful().getOutcomeDeclaration(identifier);
 				renderPrintedVariable(renderer, sb, printedVar, outcomeDeclaration, outcomeValue);
 			} else if(templateValue != null) {
-				TemplateDeclaration templateDeclaration = assessmentItem.getTemplateDeclaration(identifier);
+				TemplateDeclaration templateDeclaration = resolvedAssessmentItem.getRootNodeLookup()
+						.extractIfSuccessful().getTemplateDeclaration(identifier);
 				renderPrintedVariable(renderer, sb, printedVar, templateDeclaration, templateValue);
 			} else {
 				sb.append("(variable ").append(identifier.toString()).append(" was not found)");
@@ -394,9 +396,9 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 	
 	@Override
 	protected void renderMath(AssessmentRenderer renderer, StringOutput out, AssessmentObjectComponent component,
-			AssessmentItem assessmentItem, ItemSessionState itemSessionState, QtiNode mathElement) {
-		if(assessmentItem != null) {
-			super.renderMath(renderer, out, component, assessmentItem, itemSessionState, mathElement);
+			ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState, QtiNode mathElement) {
+		if(resolvedAssessmentItem != null) {
+			super.renderMath(renderer, out, component, resolvedAssessmentItem, itemSessionState, mathElement);
 		} else if(mathElement instanceof ForeignElement) {
 			ForeignElement fElement = (ForeignElement)mathElement;
 			boolean mi = fElement.getQtiClassName().equals("mi");
@@ -414,15 +416,15 @@ public class AssessmentTestComponentRenderer extends AssessmentObjectComponentRe
 						substituteMi(out, outcomeValue);
 					}
 				} else {
-					renderStartHtmlTag(out, component, fElement, null);
+					renderStartHtmlTag(out, component, resolvedAssessmentItem, fElement, null);
 					fElement.getChildren().forEach((child)
-							-> renderMath(renderer, out, component, assessmentItem, itemSessionState, child));
+							-> renderMath(renderer, out, component, resolvedAssessmentItem, itemSessionState, child));
 					renderEndTag(out, fElement);
 				}
 			} else {
-				renderStartHtmlTag(out, component, fElement, null);
+				renderStartHtmlTag(out, component, resolvedAssessmentItem, fElement, null);
 				fElement.getChildren().forEach((child)
-						-> renderMath(renderer, out, component, assessmentItem, itemSessionState, child));
+						-> renderMath(renderer, out, component, resolvedAssessmentItem, itemSessionState, child));
 				renderEndTag(out, fElement);
 			}
 		} else if(mathElement instanceof TextRun) {
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java
index ee314a6339377a0642bc30c7b5162952ec6214cb..9d74759ca172e39a7f897462a32b1dd197d6deb5 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponent.java
@@ -22,6 +22,7 @@ package org.olat.ims.qti21.ui.components;
 import org.olat.core.gui.UserRequest;
 
 import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentTest;
 import uk.ac.ed.ph.jqtiplus.running.ItemProcessingContext;
 import uk.ac.ed.ph.jqtiplus.running.TestSessionController;
@@ -50,6 +51,11 @@ public class AssessmentTreeComponent extends AssessmentObjectComponent {
 		this.qtiItem = qtiItem;
 	}
 	
+	@Override
+	public String relativePathTo(ResolvedAssessmentItem resolvedAssessmentItem) {
+		return "";
+	}
+
 	@Override
 	public AssessmentTreeFormItem getQtiItem() {
 		return qtiItem;
diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java
index b1581d5d5383604d7e56cd644907354dcaec889e..dfb91253ffc04cb9a7ca6dc87ee46012decd1016 100644
--- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java
+++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTreeComponentRenderer.java
@@ -36,9 +36,9 @@ import org.olat.ims.qti21.ui.CandidateSessionContext;
 import org.olat.ims.qti21.ui.QTIWorksAssessmentTestEvent.Event;
 
 import uk.ac.ed.ph.jqtiplus.node.content.variable.PrintedVariable;
-import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.test.NavigationMode;
 import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.running.ItemProcessingContext;
 import uk.ac.ed.ph.jqtiplus.running.ItemSessionController;
 import uk.ac.ed.ph.jqtiplus.running.TestSessionController;
@@ -249,8 +249,8 @@ public class AssessmentTreeComponentRenderer extends AssessmentObjectComponentRe
 	
 	@Override
 	protected void renderPrintedVariable(AssessmentRenderer renderer, StringOutput sb,
-			AssessmentObjectComponent component, AssessmentItem assessmentItem, ItemSessionState itemSessionState,
+			AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, ItemSessionState itemSessionState,
 			PrintedVariable printedVar) {
-
+		//
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java
index ffc9f5f8875094fc6570e40841442bed9d4d0c15..04006d618d8614d283791c82b378bbb77c81ada1 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java
@@ -20,7 +20,6 @@
 package org.olat.ims.qti21.ui.editor;
 
 import java.io.File;
-import java.net.URI;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -30,6 +29,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.qti21.QTI21Service;
 import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.QTI21QuestionTypeDetector;
@@ -77,6 +77,10 @@ public class AssessmentItemEditorController extends BasicController {
 	private AssessmentItemDisplayController displayCtrl;
 	private Controller itemEditor, scoreEditor, feedbackEditor;
 	
+	private final File itemFile;
+	private final File rootDirectory;
+	private final VFSContainer rootContainer;
+	
 	private AssessmentItemBuilder itemBuilder;
 	private ManifestMetadataBuilder metadataBuilder;
 	
@@ -87,9 +91,13 @@ public class AssessmentItemEditorController extends BasicController {
 	
 	
 	public AssessmentItemEditorController(UserRequest ureq, WindowControl wControl,
-			ResolvedAssessmentItem resolvedAssessmentItem, File unzippedDirectory, File itemFile) {
+			ResolvedAssessmentItem resolvedAssessmentItem,
+			File rootDirectory, VFSContainer rootContainer, File itemFile) {
 		super(ureq, wControl);
 		this.itemRef = null;
+		this.itemFile = itemFile;
+		this.rootDirectory = rootDirectory;
+		this.rootContainer = rootContainer;
 		this.resolvedAssessmentItem = resolvedAssessmentItem;
 		
 		mainVC = createVelocityContainer("assessment_item_editor");
@@ -99,7 +107,7 @@ public class AssessmentItemEditorController extends BasicController {
 
 		initItemEditor(ureq);
 		
-		displayCtrl = new AssessmentItemDisplayController(ureq, getWindowControl(), resolvedAssessmentItem, unzippedDirectory, itemFile);
+		displayCtrl = new AssessmentItemDisplayController(ureq, getWindowControl(), resolvedAssessmentItem, rootDirectory, itemFile);
 		listenTo(displayCtrl);
 		tabbedPane.addTab("Preview", displayCtrl.getInitialComponent());
 		
@@ -108,10 +116,13 @@ public class AssessmentItemEditorController extends BasicController {
 	
 	public AssessmentItemEditorController(UserRequest ureq, WindowControl wControl, RepositoryEntry testEntry,
 			ResolvedAssessmentItem resolvedAssessmentItem, AssessmentItemRef itemRef, ManifestMetadataBuilder metadataBuilder,
-			File unzippedDirectory) {
+			File rootDirectory, VFSContainer rootContainer, File itemFile) {
 		super(ureq, wControl);
 		this.itemRef = itemRef;
 		this.metadataBuilder = metadataBuilder;
+		this.itemFile = itemFile;
+		this.rootDirectory = rootDirectory;
+		this.rootContainer = rootContainer;
 		this.resolvedAssessmentItem = resolvedAssessmentItem;
 		
 		mainVC = createVelocityContainer("assessment_item_editor");
@@ -123,7 +134,7 @@ public class AssessmentItemEditorController extends BasicController {
 		
 		AssessmentEntry assessmentEntry = assessmentService.getOrCreateAssessmentEntry(getIdentity(), testEntry, null, testEntry);
 		displayCtrl = new AssessmentItemDisplayController(ureq, getWindowControl(),
-				testEntry, assessmentEntry, true, resolvedAssessmentItem, itemRef, unzippedDirectory);
+				testEntry, assessmentEntry, true, resolvedAssessmentItem, itemRef, rootDirectory);
 		listenTo(displayCtrl);
 		tabbedPane.addTab("Preview", displayCtrl.getInitialComponent());
 		
@@ -167,7 +178,8 @@ public class AssessmentItemEditorController extends BasicController {
 
 	private AssessmentItemBuilder initSingleChoiceEditors(UserRequest ureq, AssessmentItem item) {
 		SingleChoiceAssessmentItemBuilder scItemBuilder = new SingleChoiceAssessmentItemBuilder(item, qtiService.qtiSerializer());
-		itemEditor = new SingleChoiceEditorController(ureq, getWindowControl(), scItemBuilder);
+		itemEditor = new SingleChoiceEditorController(ureq, getWindowControl(), scItemBuilder,
+				rootDirectory, rootContainer, itemFile);
 		listenTo(itemEditor);
 		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), scItemBuilder, itemRef);
 		listenTo(scoreEditor);
@@ -182,7 +194,8 @@ public class AssessmentItemEditorController extends BasicController {
 	
 	private AssessmentItemBuilder initMultipleChoiceEditors(UserRequest ureq, AssessmentItem item) {
 		MultipleChoiceAssessmentItemBuilder mcItemBuilder = new MultipleChoiceAssessmentItemBuilder(item, qtiService.qtiSerializer());
-		itemEditor = new MultipleChoiceEditorController(ureq, getWindowControl(), mcItemBuilder);
+		itemEditor = new MultipleChoiceEditorController(ureq, getWindowControl(), mcItemBuilder,
+				rootDirectory, rootContainer, itemFile);
 		listenTo(itemEditor);
 		scoreEditor = new ChoiceScoreController(ureq, getWindowControl(), mcItemBuilder, itemRef);
 		listenTo(scoreEditor);
@@ -197,7 +210,8 @@ public class AssessmentItemEditorController extends BasicController {
 	
 	private AssessmentItemBuilder initKPrimChoiceEditors(UserRequest ureq, AssessmentItem item) {
 		KPrimAssessmentItemBuilder kprimItemBuilder = new KPrimAssessmentItemBuilder(item, qtiService.qtiSerializer());
-		itemEditor = new KPrimEditorController(ureq, getWindowControl(), kprimItemBuilder);
+		itemEditor = new KPrimEditorController(ureq, getWindowControl(), kprimItemBuilder,
+				rootDirectory, rootContainer, itemFile);
 		listenTo(itemEditor);
 		scoreEditor = new MinimalScoreController(ureq, getWindowControl(), kprimItemBuilder, itemRef);
 		listenTo(scoreEditor);
@@ -212,7 +226,8 @@ public class AssessmentItemEditorController extends BasicController {
 	
 	private AssessmentItemBuilder initFIBEditors(UserRequest ureq, AssessmentItem item) {
 		FIBAssessmentItemBuilder kprimItemBuilder = new FIBAssessmentItemBuilder(item, qtiService.qtiSerializer());
-		itemEditor = new FIBEditorController(ureq, getWindowControl(), kprimItemBuilder);
+		itemEditor = new FIBEditorController(ureq, getWindowControl(), kprimItemBuilder,
+				rootDirectory, rootContainer, itemFile);
 		listenTo(itemEditor);
 		scoreEditor = new FIBScoreController(ureq, getWindowControl(), kprimItemBuilder, itemRef);
 		listenTo(scoreEditor);
@@ -227,7 +242,8 @@ public class AssessmentItemEditorController extends BasicController {
 	
 	private AssessmentItemBuilder initEssayEditors(UserRequest ureq, AssessmentItem item) {
 		EssayAssessmentItemBuilder essayItemBuilder = new EssayAssessmentItemBuilder(item, qtiService.qtiSerializer());
-		itemEditor = new EssayEditorController(ureq, getWindowControl(), essayItemBuilder);
+		itemEditor = new EssayEditorController(ureq, getWindowControl(), essayItemBuilder,
+				rootDirectory, rootContainer, itemFile);
 		listenTo(itemEditor);
 		scoreEditor = new MinimalScoreController(ureq, getWindowControl(), essayItemBuilder, itemRef);
 		listenTo(scoreEditor);
@@ -271,8 +287,6 @@ public class AssessmentItemEditorController extends BasicController {
 		if(itemBuilder != null) {
 			itemBuilder.build();
 		}
-		URI itemUri = resolvedAssessmentItem.getItemLookup().getSystemId();
-		File itemFile = new File(itemUri);
 		qtiService.updateAssesmentObject(itemFile, resolvedAssessmentItem);
 	}
 
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 ca7310d77428ff376bee0c9e7bb693a53e3aa07e..899b3df5d074800c14a022e26ca2dc0a1faa0b31 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
@@ -55,6 +55,7 @@ import org.olat.core.gui.control.generic.wizard.StepRunnerCallback;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
 import org.olat.core.gui.control.generic.wizard.StepsRunContext;
 import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.ims.qti21.QTI21Constants;
 import org.olat.ims.qti21.QTI21Service;
@@ -128,6 +129,8 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 	private final LayoutMain3ColsController columnLayoutCtr;
 	
 	private final File unzippedDirRoot;
+	private final VFSContainer unzippedContRoot;
+	
 	private final RepositoryEntry testEntry;
 	private ManifestBuilder manifestBuilder;
 	private ResolvedAssessmentTest resolvedAssessmentTest;
@@ -161,6 +164,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 
 		FileResourceManager frm = FileResourceManager.getInstance();
 		unzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource());
+		unzippedContRoot = frm.unzipContainerResource(testEntry.getOlatResource());
 		updateTreeModel();
 		manifestBuilder = ManifestBuilder.read(new File(unzippedDirRoot, "imsmanifest.xml"));
 		
@@ -536,8 +540,8 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 		}
 		
 		//persist metadata
-		manifestBuilder.write(new File(unzippedDirRoot, "imsmanifest.xml"));
 		
+		doSaveManifest();
 		updateTreeModel();
 		
 		TreeNode newItemNode = menuTree.getTreeModel().getNodeById(firstItemId);
@@ -562,7 +566,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 		qtiService.updateAssesmentObject(testFile, resolvedAssessmentTest);
 
 		manifestBuilder.appendAssessmentItem(itemFile.getName());
-		manifestBuilder.write(new File(unzippedDirRoot, "imsmanifest.xml"));
+		doSaveManifest();
 		return itemRef;
 	}
 	
@@ -651,7 +655,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 			qtiService.updateAssesmentObject(testFile, resolvedAssessmentTest);
 
 			manifestBuilder.appendAssessmentItem(itemFile.getName());
-			manifestBuilder.write(new File(unzippedDirRoot, "imsmanifest.xml"));
+			doSaveManifest();
 			
 			updateTreeModel();
 			
@@ -685,7 +689,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 	}
 	
 	private void doSaveManifest() {
-		this.manifestBuilder.write(new File(unzippedDirRoot, "imsmanifest.xml"));
+		manifestBuilder.write(new File(unzippedDirRoot, "imsmanifest.xml"));
 	}
 	
 	private void doUpdate(Identifier identifier, String newTitle) {
@@ -730,9 +734,11 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 				currentEditorCtrl = new BadResourceController(ureq, getWindowControl(),
 						item.getItemLookup().getBadResourceException(), unzippedDirRoot, itemRef.getHref());
 			} else {
+				URI itemUri = resolvedAssessmentTest.getSystemIdByItemRefMap().get(itemRef);
+				File itemFile = new File(itemUri);
 				ManifestMetadataBuilder metadata = getMetadataBuilder(itemRef);
 				currentEditorCtrl = new AssessmentItemEditorController(ureq, getWindowControl(), testEntry,
-						item, itemRef, metadata, unzippedDirRoot);
+						item, itemRef, metadata, unzippedDirRoot, unzippedContRoot, itemFile);
 			}
 		}
 		
@@ -765,8 +771,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 			itemRef.setIdentifier(Identifier.parseString(itemId));
 			itemFile = new File(unzippedDirRoot, itemId + ".xml");
 			itemRef.setHref(new URI(itemFile.getName()));
-			
-			
+
 			try(OutputStream out = new FileOutputStream(itemFile)) {
 				//make the copy
 				qtiService.qtiSerializer().serializeJqtiObject(originalAssessmentItem, out);
@@ -786,7 +791,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 				qtiService.updateAssesmentObject(testFile, resolvedAssessmentTest);
 
 				manifestBuilder.appendAssessmentItem(itemFile.getName());
-				manifestBuilder.write(new File(unzippedDirRoot, "imsmanifest.xml"));
+				doSaveManifest();
 			} catch (Exception e) {
 				logError("", e);
 			}
@@ -840,7 +845,7 @@ public class AssessmentTestComposerController extends MainLayoutBasicController
 		URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId();
 		File testFile = new File(testUri);
 		qtiService.updateAssesmentObject(testFile, resolvedAssessmentTest);
-		manifestBuilder.write(new File(unzippedDirRoot, "imsmanifest.xml"));
+		doSaveManifest();
 		updateTreeModel();
 
 		if(selectedNode != null && selectedNode.getParent() != null) {
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java
index 84084426b6c87468fb8cc82fa8385f609f04124c..d5eab12e939cc788bb91fc3da405609773cba4d6 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java
@@ -19,17 +19,19 @@
  */
 package org.olat.ims.qti21.ui.editor.interactions;
 
+import java.io.File;
+
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.RichTextElement;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.xml.interactions.EssayAssessmentItemBuilder;
 import org.olat.ims.qti21.ui.editor.AssessmentTestEditorController;
@@ -47,13 +49,20 @@ public class EssayEditorController extends FormBasicController {
 	private TextElement placeholderEl;
 	private TextElement widthEl, heightEl, minWordsEl, maxWordsEl;
 	private RichTextElement textEl;
-	
+
+	private final File itemFile;
+	private final File rootDirectory;
+	private final VFSContainer rootContainer;
 	private final EssayAssessmentItemBuilder itemBuilder;
 	
-	public EssayEditorController(UserRequest ureq, WindowControl wControl, EssayAssessmentItemBuilder itemBuilder) {
+	public EssayEditorController(UserRequest ureq, WindowControl wControl, EssayAssessmentItemBuilder itemBuilder,
+			File rootDirectory, VFSContainer rootContainer, File itemFile) {
 		super(ureq, wControl);
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
+		this.itemFile = itemFile;
 		this.itemBuilder = itemBuilder;
+		this.rootDirectory = rootDirectory;
+		this.rootContainer = rootContainer;
 		initForm(ureq);
 	}
 
@@ -62,11 +71,12 @@ public class EssayEditorController extends FormBasicController {
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), formLayout);
 		titleEl.setMandatory(true);
 		
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
+
 		String description = itemBuilder.getQuestion();
-		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, null, null,
+		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, itemContainer, null,
 				formLayout, ureq.getUserSession(), getWindowControl());
-		RichTextConfiguration richTextConfig = textEl.getEditorConfiguration();
-		richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir
 		
 		String placeholder = itemBuilder.getPlaceholder();
 		placeholderEl = uifactory.addTextElement("placeholder", "fib.placeholder", 256, placeholder, formLayout);
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java
index da70fef6d09530523d5a8df52cb448941954cfc0..d27efac5c959005239d709654bc62aca63db1197 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBEditorController.java
@@ -19,6 +19,8 @@
  */
 package org.olat.ims.qti21.ui.editor.interactions;
 
+import java.io.File;
+
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -33,6 +35,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder;
 import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.TextEntry;
@@ -52,13 +55,20 @@ public class FIBEditorController extends FormBasicController {
 
 	private CloseableModalController cmc;
 	private FIBTextEntrySettingsController gapEntrySettingsCtrl;
-	
+
+	private final File itemFile;
+	private final File rootDirectory;
+	private final VFSContainer rootContainer;
 	private final FIBAssessmentItemBuilder itemBuilder;
 	
-	public FIBEditorController(UserRequest ureq, WindowControl wControl, FIBAssessmentItemBuilder itemBuilder) {
+	public FIBEditorController(UserRequest ureq, WindowControl wControl, FIBAssessmentItemBuilder itemBuilder,
+			File rootDirectory, VFSContainer rootContainer, File itemFile) {
 		super(ureq, wControl, "fib");
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
+		this.itemFile = itemFile;
 		this.itemBuilder = itemBuilder;
+		this.rootDirectory = rootDirectory;
+		this.rootContainer = rootContainer;
 		initForm(ureq);
 	}
 
@@ -72,13 +82,15 @@ public class FIBEditorController extends FormBasicController {
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), metadata);
 		titleEl.setMandatory(true);
 		
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
+		
 		String description = itemBuilder.getQuestion();
-		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, null, null,
+		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, itemContainer, null,
 				metadata, ureq.getUserSession(), getWindowControl());
 		textEl.addActionListener(FormEvent.ONCLICK);
 		RichTextConfiguration richTextConfig = textEl.getEditorConfiguration();
 		richTextConfig.enableQTITools();
-		richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir
 		
 		// Submit Button
 		FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java
index d0329b8cd8f1a7a426f78d73e27da702b841aa59..90919df195cd66560604a58fb0f2f2e8eb600d48 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java
@@ -19,6 +19,7 @@
  */
 package org.olat.ims.qti21.ui.editor.interactions;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -32,11 +33,11 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.qti21.QTI21Constants;
 import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.xml.interactions.KPrimAssessmentItemBuilder;
@@ -65,12 +66,19 @@ public class KPrimEditorController extends FormBasicController {
 	private final List<KprimWrapper> choiceWrappers = new ArrayList<>();
 
 	private int count = 0;
+	private final File itemFile;
+	private final File rootDirectory;
+	private final VFSContainer rootContainer;
 	private final KPrimAssessmentItemBuilder itemBuilder;
 	
-	public KPrimEditorController(UserRequest ureq, WindowControl wControl, KPrimAssessmentItemBuilder itemBuilder) {
+	public KPrimEditorController(UserRequest ureq, WindowControl wControl, KPrimAssessmentItemBuilder itemBuilder,
+			File rootDirectory, VFSContainer rootContainer, File itemFile) {
 		super(ureq, wControl, "simple_choices_editor");
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
+		this.itemFile = itemFile;
 		this.itemBuilder = itemBuilder;
+		this.rootDirectory = rootDirectory;
+		this.rootContainer = rootContainer;
 		initForm(ureq);
 	}
 
@@ -84,13 +92,12 @@ public class KPrimEditorController extends FormBasicController {
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), metadata);
 		titleEl.setMandatory(true);
 		
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
+		
 		String description = itemBuilder.getQuestion();
-		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, null, null,
+		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, itemContainer, null,
 				metadata, ureq.getUserSession(), getWindowControl());
-		RichTextConfiguration richTextConfig = textEl.getEditorConfiguration();
-		richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir
-				
-		//points -> in other controller
 		
 		//shuffle
 		String[] yesnoValues = new String[]{ translate("yes"), translate("no") };
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java
index 25599278e68081e8d91f3c2dd61eb1cc19e838c2..3699b3975ca35486e9c29341ebf0aa2130e4e89b 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java
@@ -19,6 +19,7 @@
  */
 package org.olat.ims.qti21.ui.editor.interactions;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -32,12 +33,12 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.qti21.model.IdentifierGenerator;
 import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.xml.AssessmentItemFactory;
@@ -64,15 +65,24 @@ public class MultipleChoiceEditorController extends FormBasicController {
 	private FormLayoutContainer answersCont;
 	private final List<SimpleChoiceWrapper> choiceWrappers = new ArrayList<>();
 	
+	private final File itemFile;
+	private final File rootDirectory;
+	private final VFSContainer rootContainer;
+	
 	private int count = 0;
 	private final MultipleChoiceAssessmentItemBuilder itemBuilder;
 	
 	private static final String[] yesnoKeys = new String[]{ "y", "n"};
 
-	public MultipleChoiceEditorController(UserRequest ureq, WindowControl wControl, MultipleChoiceAssessmentItemBuilder itemBuilder) {
+	public MultipleChoiceEditorController(UserRequest ureq, WindowControl wControl,
+			MultipleChoiceAssessmentItemBuilder itemBuilder,
+			File rootDirectory, VFSContainer rootContainer, File itemFile) {
 		super(ureq, wControl, "simple_choices_editor");
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
 		this.itemBuilder = itemBuilder;
+		this.itemFile = itemFile;
+		this.rootDirectory = rootDirectory;
+		this.rootContainer = rootContainer;
 		initForm(ureq);
 	}
 
@@ -88,13 +98,12 @@ public class MultipleChoiceEditorController extends FormBasicController {
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), metadata);
 		titleEl.setMandatory(true);
 		
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
+		
 		String description = itemBuilder.getQuestion();
-		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, null, null,
+		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, itemContainer, null,
 				metadata, ureq.getUserSession(), getWindowControl());
-		RichTextConfiguration richTextConfig = textEl.getEditorConfiguration();
-		richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir
-				
-		//points -> in other controller
 		
 		//shuffle
 		String[] yesnoValues = new String[]{ translate("yes"), translate("no") };
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java
index 1c764748636967d5accf72777fc94f1cfc5958a5..dcccb3c478a39e64662ef6d2f30339cbfa7fa59a 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java
@@ -19,6 +19,7 @@
  */
 package org.olat.ims.qti21.ui.editor.interactions;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -32,12 +33,12 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.xml.AssessmentItemFactory;
 import org.olat.ims.qti21.model.xml.interactions.SingleChoiceAssessmentItemBuilder;
@@ -63,14 +64,22 @@ public class SingleChoiceEditorController extends FormBasicController {
 	private final List<SimpleChoiceWrapper> choiceWrappers = new ArrayList<>();
 	
 	private int count = 0;
+	private final File itemFile;
+	private final File rootDirectory;
+	private final VFSContainer rootContainer;
 	private final SingleChoiceAssessmentItemBuilder itemBuilder;
 	
 	private static final String[] yesnoKeys = new String[]{ "y", "n"};
 
-	public SingleChoiceEditorController(UserRequest ureq, WindowControl wControl, SingleChoiceAssessmentItemBuilder itemBuilder) {
+	public SingleChoiceEditorController(UserRequest ureq, WindowControl wControl,
+			SingleChoiceAssessmentItemBuilder itemBuilder,
+			File rootDirectory, VFSContainer rootContainer, File itemFile) {
 		super(ureq, wControl, "simple_choices_editor");
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
 		this.itemBuilder = itemBuilder;
+		this.itemFile = itemFile;
+		this.rootDirectory = rootDirectory;
+		this.rootContainer = rootContainer;
 		initForm(ureq);
 	}
 
@@ -83,14 +92,13 @@ public class SingleChoiceEditorController extends FormBasicController {
 
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), metadata);
 		titleEl.setMandatory(true);
+
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
 		
 		String description = itemBuilder.getQuestion();
-		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, null, null,
+		textEl = uifactory.addRichTextElementForStringData("desc", "form.imd.descr", description, 8, -1, true, itemContainer, null,
 				metadata, ureq.getUserSession(), getWindowControl());
-		RichTextConfiguration richTextConfig = textEl.getEditorConfiguration();
-		richTextConfig.setFileBrowserUploadRelPath("media");// set upload dir to the media dir
-				
-		//points -> in other controller
 		
 		//shuffle
 		String[] yesnoValues = new String[]{ translate("yes"), translate("no") };
diff --git a/src/main/java/org/olat/ims/qti21/ui/rendering/XmlUtilities.java b/src/main/java/org/olat/ims/qti21/ui/rendering/XmlUtilities.java
deleted file mode 100644
index b4c1f40c007e9502d3bb0ae89470aa8967c9b114..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/ims/qti21/ui/rendering/XmlUtilities.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Copyright (c) 2012-2013, University of Edinburgh.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- *   list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice, this
- *   list of conditions and the following disclaimer in the documentation and/or
- *   other materials provided with the distribution.
- *
- * * Neither the name of the University of Edinburgh nor the names of its
- *   contributors may be used to endorse or promote products derived from this
- *   software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * This software is derived from (and contains code from) QTItools and MathAssessEngine.
- * QTItools is (c) 2008, University of Southampton.
- * MathAssessEngine is (c) 2010, University of Edinburgh.
- */
-package org.olat.ims.qti21.ui.rendering;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.XMLReader;
-
-/**
- * Some generic XML-related utilities.
- *
- * @author David McKain
- */
-public final class XmlUtilities {
-
-    public static final DocumentBuilder createNsAwareDocumentBuilder() {
-        try {
-            final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
-            documentBuilderFactory.setNamespaceAware(true);
-            return documentBuilderFactory.newDocumentBuilder();
-        }
-        catch (final ParserConfigurationException e) {
-            throw new RuntimeException("Could not create NS-aware DocumentBuilder. Check deployment/runtime ClassPath", e);
-        }
-    }
-
-    public static final XMLReader createNsAwareSaxReader(final boolean validating) {
-        try {
-            final SAXParserFactory parserFactory = SAXParserFactory.newInstance();
-            parserFactory.setNamespaceAware(true);
-            parserFactory.setValidating(validating);
-            return parserFactory.newSAXParser().getXMLReader();
-        }
-        catch (final Exception e) {
-            throw new RuntimeException("Could not create NS-aware SAXParser with validating=" + validating + ". Check deployment/runtime ClassPath", e);
-        }
-    }
-
-}