Mercurial > hg > webaudioevaluationtool
changeset 2579:d83b38564fbb
#137. Modified <commentquestion> nodes in pages to have a proper list structure. Differently labelled nodes depending on type <commentquestion>, <commentradio>. Added slider and converted project.xml to match new specifications. AB_example.xml shows new slider type
author | Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk> |
---|---|
date | Sun, 30 Oct 2016 13:57:37 +0000 |
parents | bf17cc19c1c0 |
children | a6b32c473577 |
files | js/core.js js/specification.js tests/examples/AB_example.xml tests/examples/project.xml xml/test-schema.xsd |
diffstat | 5 files changed, 376 insertions(+), 218 deletions(-) [+] |
line wrap: on
line diff
--- a/js/core.js Mon Oct 24 11:23:02 2016 +0100 +++ b/js/core.js Sun Oct 30 13:57:37 2016 +0000 @@ -2630,6 +2630,52 @@ this.resize(); }; + this.sliderBox = function (commentQuestion) { + this.specification = commentQuestion; + this.holder = document.createElement("div"); + this.holder.className = 'comment-div'; + this.string = document.createElement("span"); + this.string.innerHTML = commentQuestion.statement; + this.slider = document.createElement("input"); + this.slider.type = "range"; + this.slider.min = commentQuestion.min; + this.slider.max = commentQuestion.max; + this.slider.step = commentQuestion.step; + this.slider.value = commentQuestion.value; + var br = document.createElement('br'); + + this.holder.appendChild(this.string); + this.holder.appendChild(br); + this.holder.appendChild(this.slider); + + this.exportXMLDOM = function (storePoint) { + var root = storePoint.parent.document.createElement('comment'); + root.id = this.specification.id; + root.setAttribute('type', this.specification.type); + console.log("Question: " + this.string.textContent); + console.log("Response: " + this.slider.value); + var question = storePoint.parent.document.createElement('question'); + question.textContent = this.string.textContent; + var response = storePoint.parent.document.createElement('response'); + response.textContent = this.slider.value; + root.appendChild(question); + root.appendChild(response); + storePoint.XMLDOM.appendChild(root); + return root; + }; + this.resize = function () { + var boxwidth = (window.innerWidth - 100) / 2; + if (boxwidth >= 600) { + boxwidth = 600; + } else if (boxwidth < 400) { + boxwidth = 400; + } + this.holder.style.width = boxwidth + "px"; + this.slider.style.width = boxwidth - 24 + "px"; + }; + this.resize(); + }; + this.createCommentQuestion = function (element) { var node; if (element.type == 'question') { @@ -2638,6 +2684,8 @@ node = new this.radioBox(element); } else if (element.type == 'checkbox') { node = new this.checkboxBox(element); + } else if (element.type == 'slider') { + node = new this.sliderBox(element); } this.commentQuestions.push(node); return node;
--- a/js/specification.js Mon Oct 24 11:23:02 2016 +0100 +++ b/js/specification.js Sun Oct 30 13:57:37 2016 +0000 @@ -495,88 +495,87 @@ this.decode = function (parent, xml) { this.parent = parent; - var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); - for (var i=0; i<attributeMap.length; i++) - { - var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); - var projectAttr = xml.getAttribute(attributeName); - projectAttr = parent.processAttribute(projectAttr,attributeMap[i],parent.schema); - switch(typeof projectAttr) - { - case "number": - case "boolean": - eval('this.'+attributeName+' = '+projectAttr); - break; - case "string": - eval('this.'+attributeName+' = "'+projectAttr+'"'); - break; - } - } - + var attributeMap = this.schema.getAllElementsByTagName('xs:attribute'); + for (var i = 0; i < attributeMap.length; i++) { + var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); + var projectAttr = xml.getAttribute(attributeName); + projectAttr = parent.processAttribute(projectAttr, attributeMap[i], parent.schema); + switch (typeof projectAttr) { + case "number": + case "boolean": + eval('this.' + attributeName + ' = ' + projectAttr); + break; + case "string": + eval('this.' + attributeName + ' = "' + projectAttr + '"'); + break; + } + } + // Get the title var title = xml.getElementsByTagName('title'); if (title.length != 0 && title[0].parentElement == xml) { this.title = title[0].textContent; } - - // Get the Comment Box Prefix - var CBP = xml.getElementsByTagName('commentboxprefix'); - if (CBP.length != 0 && CBP[0].parentElement == xml) { - this.commentBoxPrefix = CBP[0].textContent; - } - - // Now decode the interfaces - var interfaceNode = xml.getElementsByTagName('interface'); - for (var i=0; i<interfaceNode.length; i++) - { - var node = new parent.interfaceNode(this.specification); - node.decode(this,interfaceNode[i],parent.schema.getAllElementsByName('interface')[1]); - this.interfaces.push(node); - } - - // Now process the survey node options - var survey = xml.getElementsByTagName('survey'); - var surveySchema = parent.schema.getAllElementsByName('survey')[0]; - for (var i=0; i<survey.length; i++){ - var location = survey[i].getAttribute('location'); - if (location == 'pre' || location == 'before') - { - if (this.preTest != null){this.errors.push("Already a pre/before test survey defined! Ignoring second!!");} - else { - this.preTest = new parent.surveyNode(this.specification); - this.preTest.decode(parent,survey[i],surveySchema); - } - } else if (location == 'post' || location == 'after') { - if (this.postTest != null){this.errors.push("Already a post/after test survey defined! Ignoring second!!");} - else { - this.postTest = new parent.surveyNode(this.specification); - this.postTest.decode(parent,survey[i],surveySchema); - } - } - } - - // Now process the audioelement tags - var audioElements = xml.getElementsByTagName('audioelement'); - for (var i=0; i<audioElements.length; i++) - { - var node = new this.audioElementNode(this.specification); - node.decode(this,audioElements[i]); - this.audioElements.push(node); - } - - // Now decode the commentquestions - var commentQuestions = xml.getElementsByTagName('commentquestion'); - for (var i=0; i<commentQuestions.length; i++) - { - var node = new this.commentQuestionNode(this.specification); - node.decode(parent,commentQuestions[i]); - this.commentQuestions.push(node); - } - }; - - this.encode = function(root) - { - var AHNode = root.createElement("page"); + + // Get the Comment Box Prefix + var CBP = xml.getElementsByTagName('commentboxprefix'); + if (CBP.length != 0 && CBP[0].parentElement == xml) { + this.commentBoxPrefix = CBP[0].textContent; + } + + // Now decode the interfaces + var interfaceNode = xml.getElementsByTagName('interface'); + for (var i = 0; i < interfaceNode.length; i++) { + var node = new parent.interfaceNode(this.specification); + node.decode(this, interfaceNode[i], parent.schema.getAllElementsByName('interface')[1]); + this.interfaces.push(node); + } + + // Now process the survey node options + var survey = xml.getElementsByTagName('survey'); + var surveySchema = parent.schema.getAllElementsByName('survey')[0]; + for (var i = 0; i < survey.length; i++) { + var location = survey[i].getAttribute('location'); + if (location == 'pre' || location == 'before') { + if (this.preTest != null) { + this.errors.push("Already a pre/before test survey defined! Ignoring second!!"); + } else { + this.preTest = new parent.surveyNode(this.specification); + this.preTest.decode(parent, survey[i], surveySchema); + } + } else if (location == 'post' || location == 'after') { + if (this.postTest != null) { + this.errors.push("Already a post/after test survey defined! Ignoring second!!"); + } else { + this.postTest = new parent.surveyNode(this.specification); + this.postTest.decode(parent, survey[i], surveySchema); + } + } + } + + // Now process the audioelement tags + var audioElements = xml.getElementsByTagName('audioelement'); + for (var i = 0; i < audioElements.length; i++) { + var node = new this.audioElementNode(this.specification); + node.decode(this, audioElements[i]); + this.audioElements.push(node); + } + + // Now decode the commentquestions + var cqNode = xml.getElementsByTagName('commentquestions'); + if (cqNode.length != 0) { + cqNode = cqNode[0]; + var commentQuestions = cqNode.children; + for (var i = 0; i < commentQuestions.length; i++) { + var node = new this.commentQuestionNode(this.specification); + node.decode(parent, commentQuestions[i]); + this.commentQuestions.push(node); + } + } + }; + + this.encode = function (root) { + var AHNode = root.createElement("page"); // First decode the attributes var attributes = this.schema.getAllElementsByTagName('xs:attribute'); for (var i = 0; i < attributes.length; i++) { @@ -617,26 +616,73 @@ this.id = null; this.name = undefined; this.type = undefined; - this.options = []; this.statement = undefined; this.schema = specification.schema.getAllElementsByName('commentquestion')[0]; this.decode = function (parent, xml) { this.id = xml.id; this.name = xml.getAttribute('name'); - this.type = xml.getAttribute('type'); + switch (xml.nodeName) { + case "commentradio": + this.type = "radio"; + this.options = []; + break; + case "commentcheckbox": + this.type = "checkbox"; + this.options = []; + break; + case "commentslider": + this.type = "slider"; + this.min = undefined; + this.max = undefined; + this.step = undefined; + break; + case "commentquestion": + default: + this.type = "question"; + break; + } this.statement = xml.getElementsByTagName('statement')[0].textContent; - var optNodes = xml.getElementsByTagName('option'); - for (var i = 0; i < optNodes.length; i++) { - var optNode = optNodes[i]; - this.options.push({ - name: optNode.getAttribute('name'), - text: optNode.textContent - }); + if (this.type == "radio" || this.type == "checkbox") { + var optNodes = xml.getElementsByTagName('option'); + for (var i = 0; i < optNodes.length; i++) { + var optNode = optNodes[i]; + this.options.push({ + name: optNode.getAttribute('name'), + text: optNode.textContent + }); + } + } + if (this.type == "slider") { + this.min = Number(xml.getAttribute("min")); + this.max = Number(xml.getAttribute("max")); + this.step = Number(xml.getAttribute("step")); + if (this.step == undefined) { + this.step = 1; + } + this.value = Number(xml.getAttribute("value")); + if (this.value == undefined) { + this.value = min; + } } }; this.encode = function (root) { - var node = root.createElement("commentquestion"); + var node; + switch (this.type) { + case "radio": + node = root.createElement("commentradio"); + break; + case "checkbox": + node = root.createElement("commentcheckbox"); + break; + case "slider": + node = root.createElement("commentslider"); + break; + case "question": + default: + node = root.createElement("commentquestion"); + break; + } node.id = this.id; node.setAttribute("type", this.type); if (this.name != undefined) { @@ -645,11 +691,23 @@ var statement = root.createElement("statement"); statement.textContent = this.statement; node.appendChild(statement); - for (var option of this.options) { - var child = root.createElement("option"); - child.setAttribute("name", option.name); - child.textContent = option.text; - node.appendChild(child); + if (this.type == "radio" || this.type == "checkbox") { + for (var option of this.options) { + var child = root.createElement("option"); + child.setAttribute("name", option.name); + child.textContent = option.text; + node.appendChild(child); + } + } + if (this.type == "slider") { + node.setAttribute("min", this.min); + node.setAttribute("max", this.max); + if (this.step !== 1) { + node.setAttribute("step", this.step); + } + if (this.value !== this.min) { + node.setAttribute("value", this.value); + } } return node; };
--- a/tests/examples/AB_example.xml Mon Oct 24 11:23:02 2016 +0100 +++ b/tests/examples/AB_example.xml Sun Oct 30 13:57:37 2016 +0000 @@ -1,97 +1,102 @@ <?xml version="1.0" encoding="utf-8"?> -<waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="AB" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" playOne="true"> - <survey location="before"> - <surveyentry type="question" id="sessionId" mandatory="true"> - <statement>Please enter your name.</statement> - </surveyentry> - <surveyentry type="checkbox" id="checkboxtest" mandatory="true"> - <statement>Please select with which activities you have any experience (example checkbox question)</statement> - <option name="musician">Playing a musical instrument</option> - <option name="soundengineer">Recording or mixing audio</option> - <option name="developer">Developing audio software</option> - <option name="hwdesigner">Designing or building audio hardware</option> - <option name="researcher">Research in the field of audio</option> - </surveyentry> - <surveyentry type="statement" id="test-intro"> - <statement>This is an example of an 'AB'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="location" mandatory="true" boxsize="large"> - <statement>Please enter your location. (example mandatory text question)</statement> - </surveyentry> - <surveyentry type="number" id="age" min="0"> - <statement>Please enter your age (example non-mandatory number question)</statement> - </surveyentry> - <surveyentry type="radio" id="rating"> - <statement>Please rate this interface (example radio button question)</statement> - <option name="bad">Bad</option> - <option name="poor">Poor</option> - <option name="good">Good</option> - <option name="great">Great</option> - </surveyentry> - <surveyentry type="statement" id="test-thank-you"> - <statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement> - </surveyentry> - </survey> - <metric> - <metricenable>testTimer</metricenable> - <metricenable>elementTimer</metricenable> - <metricenable>elementInitialPosition</metricenable> - <metricenable>elementTracker</metricenable> - <metricenable>elementFlagListenedTo</metricenable> - <metricenable>elementFlagMoved</metricenable> - <metricenable>elementListenTracker</metricenable> - </metric> - <interface> - <interfaceoption type="check" name="fragmentMoved"/> - <interfaceoption type="check" name="scalerange" min="25" max="75"/> - <interfaceoption type="show" name='playhead'/> - <interfaceoption type="show" name="page-count"/> - <interfaceoption type="show" name='volume'/> - <interfaceoption type="show" name='comments'/> - </interface> - </setup> - <page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12"> - <commentboxprefix>Comment on fragment</commentboxprefix> - <interface> - <title>Depth</title> - </interface> - <audioelement url="0.wav" id="track-0"/> - <audioelement url="1.wav" id="track-1"/> - <survey location="before"> - <surveyentry type="statement" id="test-0-intro"> - <statement>A two way comparison using randomised element order, automatic loudness and synchronised looping.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="genre-0" mandatory="true"> - <statement>Please enter the genre.</statement> - </surveyentry> - </survey> - </page> - <page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false' loudness="-12"> - <commentboxprefix>Comment on fragment</commentboxprefix> - <interface> - <title>Depth</title> - </interface> - <audioelement url="0.wav" id="track-2"/> - <audioelement url="1.wav" id="track-3"/> - <audioelement url="2.wav" id="track-4"/> - <audioelement url="3.wav" id="track-5"/> - <audioelement url="4.wav" id="track-6"/> - <audioelement url="5.wav" id="track-7"/> - <audioelement url="6.wav" id="track-8"/> - <survey location="before"> - <surveyentry type="statement" id="test-1-intro"> - <statement>A 7 way comparison using randomised element order and synchronised looping.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="genre-1" mandatory="true"> - <statement>Please enter the genre.</statement> - </surveyentry> - </survey> - </page> -</waet> \ No newline at end of file + <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> + <setup interface="AB" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" playOne="true"> + <survey location="before"> + <surveyentry type="question" id="sessionId" mandatory="true"> + <statement>Please enter your name.</statement> + </surveyentry> + <surveyentry type="checkbox" id="checkboxtest" mandatory="true"> + <statement>Please select with which activities you have any experience (example checkbox question)</statement> + <option name="musician">Playing a musical instrument</option> + <option name="soundengineer">Recording or mixing audio</option> + <option name="developer">Developing audio software</option> + <option name="hwdesigner">Designing or building audio hardware</option> + <option name="researcher">Research in the field of audio</option> + </surveyentry> + <surveyentry type="statement" id="test-intro"> + <statement>This is an example of an 'AB'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="location" mandatory="true" boxsize="large"> + <statement>Please enter your location. (example mandatory text question)</statement> + </surveyentry> + <surveyentry type="number" id="age" min="0"> + <statement>Please enter your age (example non-mandatory number question)</statement> + </surveyentry> + <surveyentry type="radio" id="rating"> + <statement>Please rate this interface (example radio button question)</statement> + <option name="bad">Bad</option> + <option name="poor">Poor</option> + <option name="good">Good</option> + <option name="great">Great</option> + </surveyentry> + <surveyentry type="statement" id="test-thank-you"> + <statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement> + </surveyentry> + </survey> + <metric> + <metricenable>testTimer</metricenable> + <metricenable>elementTimer</metricenable> + <metricenable>elementInitialPosition</metricenable> + <metricenable>elementTracker</metricenable> + <metricenable>elementFlagListenedTo</metricenable> + <metricenable>elementFlagMoved</metricenable> + <metricenable>elementListenTracker</metricenable> + </metric> + <interface> + <interfaceoption type="check" name="fragmentMoved" /> + <interfaceoption type="check" name="scalerange" min="25" max="75" /> + <interfaceoption type="show" name='playhead' /> + <interfaceoption type="show" name="page-count" /> + <interfaceoption type="show" name='volume' /> + <interfaceoption type="show" name='comments' /> + </interface> + </setup> + <page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12"> + <commentboxprefix>Comment on fragment</commentboxprefix> + <interface> + <title>Depth</title> + </interface> + <audioelement url="0.wav" id="track-0" /> + <audioelement url="1.wav" id="track-1" /> + <commentquestions> + <commentslider id="slider" min="0" max="100"> + <statement>Test</statement> + </commentslider> + </commentquestions> + <survey location="before"> + <surveyentry type="statement" id="test-0-intro"> + <statement>A two way comparison using randomised element order, automatic loudness and synchronised looping.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="genre-0" mandatory="true"> + <statement>Please enter the genre.</statement> + </surveyentry> + </survey> + </page> + <page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false' loudness="-12"> + <commentboxprefix>Comment on fragment</commentboxprefix> + <interface> + <title>Depth</title> + </interface> + <audioelement url="0.wav" id="track-2" /> + <audioelement url="1.wav" id="track-3" /> + <audioelement url="2.wav" id="track-4" /> + <audioelement url="3.wav" id="track-5" /> + <audioelement url="4.wav" id="track-6" /> + <audioelement url="5.wav" id="track-7" /> + <audioelement url="6.wav" id="track-8" /> + <survey location="before"> + <surveyentry type="statement" id="test-1-intro"> + <statement>A 7 way comparison using randomised element order and synchronised looping.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="genre-1" mandatory="true"> + <statement>Please enter the genre.</statement> + </surveyentry> + </survey> + </page> + </waet>
--- a/tests/examples/project.xml Mon Oct 24 11:23:02 2016 +0100 +++ b/tests/examples/project.xml Sun Oct 30 13:57:37 2016 +0000 @@ -111,24 +111,26 @@ <audioelement url="4.wav" gain="0.0" id="track-9"/> <audioelement url="5.wav" gain="0.0" id="track-10"/> <audioelement url="6.wav" gain="0.0" id="track-11" type="outside-reference"/> - <commentquestion id='mixingExperience' type="question"> - <statement>What is your general experience with numbers?</statement> - </commentquestion> - <commentquestion id="preference" type="radio"> - <statement>Please enter your overall preference</statement> - <option name="worst">Very Bad</option> - <option name="bad"></option> - <option name="OK">OK</option> - <option name="Good"></option> - <option name="Great">Great</option> - </commentquestion> - <commentquestion id="character" type="checkbox"> - <statement>Please describe the overall character</statement> - <option name="funky">Funky</option> - <option name="mellow">Mellow</option> - <option name="laidback">Laid back</option> - <option name="heavy">Heavy</option> - </commentquestion> + <commentquestions> + <commentquestion id='mixingExperience'> + <statement>What is your general experience with numbers?</statement> + </commentquestion> + <commentradio id="preference"> + <statement>Please enter your overall preference</statement> + <option name="worst">Very Bad</option> + <option name="bad"></option> + <option name="OK">OK</option> + <option name="Good"></option> + <option name="Great">Great</option> + </commentradio> + <commentcheckbox id="character" type="checkbox"> + <statement>Please describe the overall character</statement> + <option name="funky">Funky</option> + <option name="mellow">Mellow</option> + <option name="laidback">Laid back</option> + <option name="heavy">Heavy</option> + </commentcheckbox> + </commentquestions> <survey location="before"> <surveyentry type="statement" id="test-1-intro"> <statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement>
--- a/xml/test-schema.xsd Mon Oct 24 11:23:02 2016 +0100 +++ b/xml/test-schema.xsd Sun Oct 30 13:57:37 2016 +0000 @@ -75,7 +75,7 @@ <xs:element name="commentboxprefix" type="xs:string" minOccurs="0" maxOccurs="1" /> <xs:element ref="interface" minOccurs="1" maxOccurs="unbounded" /> <xs:element ref="audioelement" minOccurs="1" maxOccurs="unbounded" /> - <xs:element ref="commentquestion" minOccurs="0" maxOccurs="unbounded" /> + <xs:element ref="commentquestions" minOccurs="0" maxOccurs="1" /> <xs:element ref="survey" minOccurs="0" maxOccurs="2" /> </xs:sequence> <xs:attribute ref="id" use="required" /> @@ -206,10 +206,21 @@ </xs:complexType> </xs:element> - <xs:element name="commentquestion"> + <xs:element name="commentquestions"> + <xs:complexType> + <xs:choice maxOccurs="unbounded"> + <xs:element name="commentquestion" maxOccurs="unbounded" /> + <xs:element name="commentradio" maxOccurs="unbounded" /> + <xs:element name="commentcheckbox" maxOccurs="unbounded" /> + <xs:element name="commentslider" maxOccurs="unbounded" /> + </xs:choice> + </xs:complexType> + </xs:element> + + <xs:element name="commentradio"> <xs:complexType> <xs:sequence> - <xs:element ref="statement" minOccurs="0" maxOccurs="1" /> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:simpleContent> @@ -222,15 +233,49 @@ </xs:sequence> <xs:attribute ref="id" use="optional" /> <xs:attribute ref="name" use="optional" /> - <xs:attribute name="type" default="question"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="question" /> - <xs:enumeration value="radio" /> - <xs:enumeration value="checkbox" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> + </xs:complexType> + </xs:element> + + <xs:element name="commentcheckbox"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="name" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute ref="id" use="optional" /> + <xs:attribute ref="name" use="optional" /> + </xs:complexType> + </xs:element> + + <xs:element name="commentquestion"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + </xs:sequence> + <xs:attribute ref="id" use="optional" /> + <xs:attribute ref="name" use="optional" /> + </xs:complexType> + </xs:element> + + <xs:element name="commentslider"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + </xs:sequence> + <xs:attribute ref="id" use="optional" /> + <xs:attribute ref="name" use="optional" /> + <xs:attribute name="min" type="xs:decimal" use="required" /> + <xs:attribute name="max" type="xs:decimal" use="required" /> + <xs:attribute name="step" type="xs:decimal" use="optional" default="1" /> + <xs:attribute name="value" type="xs:decimal" use="optional" /> </xs:complexType> </xs:element>