From 1cd8c3bb4fc484f4d7c0d28e574d5d694dfcae74 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Fri, 26 Feb 2016 11:02:40 +0100 Subject: [PATCH] OO-1593: fix annoying encoding and recurrent namespaces issues --- .../richText/RichTextConfiguration.java | 5 +- .../model/xml/AssessmentHtmlBuilder.java | 92 +++++++++++++++---- .../model/xml/AssessmentItemFactory.java | 17 ++-- .../FIBAssessmentItemBuilder.java | 2 + 4 files changed, 89 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java index 7e8c299e2aa..7db5be2da20 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextConfiguration.java @@ -98,8 +98,7 @@ public class RichTextConfiguration implements Disposable { private static final String TABFOCUS_SETTINGS_PREV_NEXT = ":prev,:next"; // Valid elements private static final String EXTENDED_VALID_ELEMENTS = "extended_valid_elements"; - private static final String EXTENDED_VALID_ELEMENTS_VALUE_FULL = "script[src|type|defer],form[*],input[*],a[*],p[*],#comment[*],img[*],iframe[*],map[*],area[*],textEntryInteraction[*]"; - private static final String CUSTOM_ELEMENTS = "textEntryInteraction"; + private static final String EXTENDED_VALID_ELEMENTS_VALUE_FULL = "script[src|type|defer],form[*],input[*],a[*],p[*],#comment[*],img[*],iframe[*],map[*],area[*],textentryinteraction[*]"; private static final String INVALID_ELEMENTS = "invalid_elements"; private static final String INVALID_ELEMENTS_FORM_MINIMALISTIC_VALUE_UNSAVE = "iframe,script,@[on*],object,embed"; private static final String INVALID_ELEMENTS_FORM_SIMPLE_VALUE_UNSAVE = "iframe,script,@[on*],object,embed"; @@ -654,7 +653,7 @@ public class RichTextConfiguration implements Disposable { public void enableQTITools() { tinyConfig = tinyConfig.enableQTITools(); - setQuotedConfigValue("custom_elements", "~textentryinteraction,~textEntryInteraction"); + setQuotedConfigValue("custom_elements", "~textentryinteraction"); setQuotedConfigValue("extended_valid_elements", "textentryinteraction[*]"); } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java index 5c12f1f1425..2687c2e9aa0 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java @@ -33,9 +33,9 @@ import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.filter.FilterFactory; +import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.Attributes; import org.xml.sax.InputSource; @@ -117,25 +117,37 @@ public class AssessmentHtmlBuilder { } else { htmlFragment = "<p>" + htmlFragment + "</p>"; } - //wrap around <html> to have a root element + //wrap around <html> to have a root element for neko Document document = filter("<html>" + htmlFragment + "</html>"); Element docElement = document.getDocumentElement(); - Node pEl = docElement.getFirstChild(); - NamedNodeMap attrs = pEl.getAttributes(); - for(int i=0; i<attrs.getLength(); i++) { - Node attr = attrs.item(i); - System.out.println(attr); - } - + cleanUpNamespaces(docElement); parent.getNodeGroups().load(docElement, new HTMLLoadingContext()); } } + + private void cleanUpNamespaces(Element element) { + Attr xsiattr = element.getAttributeNode("xmlns:xsi"); + if(xsiattr != null && "http://www.w3.org/2001/XMLSchema-instance".equals(xsiattr.getValue())) { + element.removeAttribute("xmlns:xsi"); + } + Attr attr = element.getAttributeNode("xmlns"); + if(attr != null && "http://www.imsglobal.org/xsd/imsqti_v2p1".equals(attr.getValue())) { + element.removeAttribute("xmlns"); + } + + for(Node child=element.getFirstChild(); child != null; child = child.getNextSibling()) { + if(child instanceof Element) { + cleanUpNamespaces((Element)child); + } + } + } private Document filter(String content) { try { SAXParser parser = new SAXParser(); parser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower"); parser.setFeature("http://cyberneko.org/html/features/balance-tags/document-fragment", true); + parser.setProperty("http://cyberneko.org/html/properties/default-encoding", "UTF-8"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); @@ -156,6 +168,16 @@ public class AssessmentHtmlBuilder { } } + /** + * Convert:<br> + * <ul> + * <li>textentryinteraction -> camel cased textEntryInteraction</li> + * </ul> + * + * Initial date: 26.02.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ private static class HtmlToDomBuilderHandler extends SimpleDomBuilderHandler { public HtmlToDomBuilderHandler(Document document) { @@ -170,9 +192,27 @@ public class AssessmentHtmlBuilder { } super.startElement(uri, localName, qName, attributes); } + + @Override + public void endElement(String uri, String localName, String qName) { + if("textentryinteraction".equals(localName)) { + localName = qName = "textEntryInteraction"; + } + super.endElement(uri, localName, qName); + } } - + /** + * Convert:<br> + * <ul> + * <li>responseidentifier -> camel cased responseIdentifier</li> + * <li>and other attributes of textEntryInteraction</li> + * </ul> + * + * Initial date: 26.02.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ private static class AttributesDelegate implements Attributes { private final Attributes attributes; @@ -181,10 +221,12 @@ public class AssessmentHtmlBuilder { this.attributes = attributes; } + @Override public int getLength() { return attributes.getLength(); } + @Override public String getURI(int index) { return attributes.getURI(index); } @@ -192,48 +234,64 @@ public class AssessmentHtmlBuilder { @Override public String getLocalName(int index) { String localName = attributes.getLocalName(index); - if("responseidentifier".equals(localName)) { - localName = "responseIdentifier"; - } - return localName; + return translateAttributeName(localName); } + @Override public String getQName(int index) { String qName = attributes.getQName(index); - if("responseidentifier".equals(qName)) { - qName = "responseIdentifier"; + return translateAttributeName(qName); + } + + private final String translateAttributeName(String attrName) { + if(attrName != null) { + switch(attrName) { + case "responseidentifier": return "responseIdentifier"; + case "placeholdertext": return "placeholderText"; + case "expectedlength": return "expectedLength"; + case "patternmask": return "patternMask"; + default: return attrName; + } } - return qName; + return attrName; } + @Override public String getType(int index) { return attributes.getType(index); } + @Override public String getValue(int index) { return attributes.getValue(index); } + @Override public int getIndex(String uri, String localName) { return attributes.getIndex(uri, localName); } + @Override public int getIndex(String qName) { return attributes.getIndex(qName.toLowerCase()); } + @Override public String getType(String uri, String localName) { return attributes.getType(uri, localName); } + @Override public String getType(String qName) { return attributes.getType(qName); } + @Override public String getValue(String uri, String localName) { return attributes.getValue(uri, localName); } + @Override public String getValue(String qName) { return attributes.getValue(qName); } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java index a94d869f4c2..55bf0ceb1f2 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentItemFactory.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import org.olat.core.helpers.Settings; +import org.olat.core.util.StringHelper; import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.model.IdentifierGenerator; import org.olat.ims.qti21.model.QTI21QuestionType; @@ -180,7 +181,7 @@ public class AssessmentItemFactory { } public static ResponseDeclaration createTextEntryResponseDeclaration(AssessmentItem assessmentItem, - Identifier declarationId, String response, Double maxScore, boolean caseSensitive, + Identifier declarationId, String response, Double score, boolean caseSensitive, List<TextEntryAlternative> alternatives) { ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem); responseDeclaration.setIdentifier(declarationId); @@ -200,7 +201,7 @@ public class AssessmentItemFactory { {//map correct response MapEntry mapEntry = new MapEntry(mapping); mapEntry.setMapKey(new StringValue(response)); - mapEntry.setMappedValue(maxScore); + mapEntry.setMappedValue(score); mapEntry.setCaseSensitive(new Boolean(caseSensitive)); mapping.getMapEntries().add(mapEntry); } @@ -208,11 +209,13 @@ public class AssessmentItemFactory { //map alternatives if(alternatives != null && alternatives.size() > 0) { for(TextEntryAlternative alternative:alternatives) { - MapEntry mapEntry = new MapEntry(mapping); - mapEntry.setMapKey(new StringValue(alternative.getAlternative())); - mapEntry.setMappedValue(maxScore); - mapEntry.setCaseSensitive(new Boolean(caseSensitive)); - mapping.getMapEntries().add(mapEntry); + if(StringHelper.containsNonWhitespace(alternative.getAlternative())) { + MapEntry mapEntry = new MapEntry(mapping); + mapEntry.setMapKey(new StringValue(alternative.getAlternative())); + mapEntry.setMappedValue(score); + mapEntry.setCaseSensitive(new Boolean(caseSensitive)); + mapping.getMapEntries().add(mapEntry); + } } } diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java index 42ea069a993..43f9a47cd59 100644 --- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java +++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java @@ -194,6 +194,8 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder { alternative.setScore(mapEntry.getMappedValue()); alternatives.add(alternative); mappedScore += mapEntry.getMappedValue(); + } else if(alt.equals(solution)) { + textEntry.setScore(mapEntry.getMappedValue()); } } -- GitLab