Mercurial > hg > webaudioevaluationtool
changeset 2223:6c98ec540504
Merge branch 'master' of https://github.com/BrechtDeMan/WebAudioEvaluationTool
author | www-data <www-data@sucuk.dcs.qmul.ac.uk> |
---|---|
date | Thu, 14 Apr 2016 13:20:58 +0100 |
parents | 77681b87c99d (current diff) 4d1aa94202e3 (diff) |
children | d61c33cd560a |
files | scripts/pythonServer-3.py scripts/pythonServer-legacy.py |
diffstat | 11 files changed, 572 insertions(+), 557 deletions(-) [+] |
line wrap: on
line diff
--- a/core.js Wed Apr 13 16:20:56 2016 +0100 +++ b/core.js Thu Apr 14 13:20:58 2016 +0100 @@ -492,10 +492,59 @@ return Math.pow(10,gain/20.0); } +function secondsToSamples(time,fs) { + return Math.round(time*fs); +} + +function samplesToSeconds(samples,fs) { + return samples / fs; +} + function randomString(length) { return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1); } +function randomiseOrder(input) +{ + // This takes an array of information and randomises the order + var N = input.length; + + var inputSequence = []; // For safety purposes: keep track of randomisation + for (var counter = 0; counter < N; ++counter) + inputSequence.push(counter) // Fill array + var inputSequenceClone = inputSequence.slice(0); + + var holdArr = []; + var outputSequence = []; + for (var n=0; n<N; n++) + { + // First pick a random number + var r = Math.random(); + // Multiply and floor by the number of elements left + r = Math.floor(r*input.length); + // Pick out that element and delete from the array + holdArr.push(input.splice(r,1)[0]); + // Do the same with sequence + outputSequence.push(inputSequence.splice(r,1)[0]); + } + console.log(inputSequenceClone.toString()); // print original array to console + console.log(outputSequence.toString()); // print randomised array to console + return holdArr; +} + +function randomSubArray(array,num) { + if (num > array.length) { + num = array.length; + } + var ret = []; + while (num > 0) { + var index = Math.floor(Math.random() * array.length); + ret.push( array.splice(index,1)[0] ); + num--; + } + return ret; +} + function interfacePopup() { // Creates an object to manage the popup this.popup = null; @@ -556,12 +605,14 @@ }; this.hidePopup = function(){ - this.popup.style.zIndex = -1; - this.popup.style.visibility = 'hidden'; - var blank = document.getElementsByClassName('testHalt')[0]; - blank.style.zIndex = -2; - blank.style.visibility = 'hidden'; - this.buttonPrevious.style.visibility = 'inherit'; + if (this.popup) { + this.popup.style.zIndex = -1; + this.popup.style.visibility = 'hidden'; + var blank = document.getElementsByClassName('testHalt')[0]; + blank.style.zIndex = -2; + blank.style.visibility = 'hidden'; + this.buttonPrevious.style.visibility = 'inherit'; + } }; this.postNode = function() { @@ -850,43 +901,68 @@ this.currentStatePosition = null; this.currentStore = null; this.initialise = function(){ - + // Get the data from Specification - var pageHolder = []; + var pagePool = []; + var pageInclude = []; for (var page of specification.pages) { - var repeat = page.repeatCount; - while(repeat >= 0) - { - pageHolder.push(page); - repeat--; + if (page.alwaysInclude) { + pageInclude.push(page); + } else { + pagePool.push(page); } } + + // Find how many are left to get + var numPages = specification.poolSize; + if (numPages > pagePool.length) { + console.log("WARNING - You have specified more pages in <setup poolSize> than you have created!!"); + numPages = specification.pages.length; + } + if (specification.poolSize == 0) { + numPages = specification.pages.length; + } + numPages -= pageInclude.length; + + if (numPages > 0) { + // Go find the rest of the pages from the pool + var subarr = null; + if (specification.randomiseOrder) { + // Append a random sub-array + subarr = randomSubArray(pagePool,numPages); + } else { + // Append the matching number + subarr = pagePool.slice(0,numPages); + } + pageInclude = pageInclude.concat(subarr); + } + + // We now have our selected pages in pageInclude array if (specification.randomiseOrder) { - pageHolder = randomiseOrder(pageHolder); + pageInclude = randomiseOrder(pageInclude); } - for (var i=0; i<pageHolder.length; i++) + for (var i=0; i<pageInclude.length; i++) { - if (specification.testPages <= i && specification.testPages != 0) {break;} - pageHolder[i].presentedId = i; - this.stateMap.push(pageHolder[i]); - storage.createTestPageStore(pageHolder[i]); - for (var element of pageHolder[i].audioElements) { - var URL = pageHolder[i].hostURL + element.url; - var buffer = null; - for (var buffObj of audioEngineContext.buffers) { - if (URL == buffObj.url) { - buffer = buffObj; - break; + pageInclude[i].presentedId = i; + this.stateMap.push(pageInclude[i]); + // For each selected page, we must get the sub pool + if (pageInclude[i].poolSize != 0 && pageInclude[i].poolSize != pageInclude[i].audioElements.length) { + var elemInclude = []; + var elemPool = []; + for (var elem of pageInclude[i].audioElements) { + if (elem.include || elem.type != "normal") { + elemInclude.push(elem); + } else { + elemPool.push(elem); } } - if (buffer == null) { - buffer = new audioEngineContext.bufferObj(); - buffer.getMedia(URL); - audioEngineContext.buffers.push(buffer); - } + var numElems = pageInclude[i].poolSize - elemInclude.length; + pageInclude[i].audioElements = elemInclude.concat(randomSubArray(elemPool,numElems)); } + storage.createTestPageStore(pageInclude[i]); + audioEngineContext.loadPageData(pageInclude[i]); } if (specification.preTest != null) {this.preTestSurvey = specification.preTest;} @@ -1170,8 +1246,56 @@ // The buffer is already ready, trigger bufferLoaded audioObject.bufferLoaded(this); } + }; + + this.copyBuffer = function(preSilenceTime,postSilenceTime) { + // Copies the entire bufferObj. + if (preSilenceTime == undefined) {preSilenceTime = 0;} + if (postSilenceTime == undefined) {postSilenceTime = 0;} + var copy = new this.constructor(); + copy.url = this.url; + var preSilenceSamples = secondsToSamples(preSilenceTime,this.buffer.sampleRate); + var postSilenceSamples = secondsToSamples(postSilenceTime,this.buffer.sampleRate); + var newLength = this.buffer.length+preSilenceSamples+postSilenceSamples; + copy.buffer = audioContext.createBuffer(this.buffer.numberOfChannels, newLength, this.buffer.sampleRate); + // Now we can use some efficient background copy schemes if we are just padding the end + if (preSilenceSamples == 0 && typeof copy.buffer.copyToChannel == "function") { + for (var c=0; c<this.buffer.numberOfChannels; c++) { + copy.buffer.copyToChannel(this.buffer.getChannelData(c),c); + } + } else { + for (var c=0; c<this.buffer.numberOfChannels; c++) { + var src = this.buffer.getChannelData(c); + var dst = copy.buffer.getChannelData(c); + for (var n=0; n<src.length; n++) + dst[n+preSilenceSamples] = src[n]; + } + } + // Copy in the rest of the buffer information + copy.buffer.lufs = this.buffer.lufs; + copy.buffer.playbackGain = this.buffer.playbackGain; + return copy; } }; + + this.loadPageData = function(page) { + // Load the URL from pages + for (var element of page.audioElements) { + var URL = page.hostURL + element.url; + var buffer = null; + for (var buffObj of this.buffers) { + if (URL == buffObj.url) { + buffer = buffObj; + break; + } + } + if (buffer == null) { + buffer = new this.bufferObj(); + buffer.getMedia(URL); + this.buffers.push(buffer); + } + } + }; this.play = function(id) { // Start the timer and set the audioEngine state to playing (1) @@ -1191,16 +1315,16 @@ this.timer.startTest(); if (id == undefined) { id = -1; - console.log('FATAL - Passed id was undefined - AudioEngineContext.play(id)'); + console.error('FATAL - Passed id was undefined - AudioEngineContext.play(id)'); return; } else { interfaceContext.playhead.setTimePerPixel(this.audioObjects[id]); } if (this.loopPlayback) { - var setTime = audioContext.currentTime; + var setTime = audioContext.currentTime+specification.crossFade; for (var i=0; i<this.audioObjects.length; i++) { - this.audioObjects[i].play(setTime); + this.audioObjects[i].play(audioContext.currentTime); if (id == i) { this.audioObjects[i].loopStart(setTime); } else { @@ -1208,7 +1332,7 @@ } } } else { - var setTime = audioContext.currentTime+0.1; + var setTime = audioContext.currentTime+specification.crossFade; for (var i=0; i<this.audioObjects.length; i++) { if (i != id) { @@ -1314,6 +1438,7 @@ this.setSynchronousLoop = function() { // Pads the signals so they are all exactly the same length + // Get the length of the longest signal. var length = 0; var maxId; for (var i=0; i<this.audioObjects.length; i++) @@ -1325,20 +1450,10 @@ } } // Extract the audio and zero-pad - for (var i=0; i<this.audioObjects.length; i++) + for (var ao of this.audioObjects) { - var orig = this.audioObjects[i].buffer.buffer; - var hold = audioContext.createBuffer(orig.numberOfChannels,length,orig.sampleRate); - for (var c=0; c<orig.numberOfChannels; c++) - { - var inData = hold.getChannelData(c); - var outData = orig.getChannelData(c); - for (var n=0; n<orig.length; n++) - {inData[n] = outData[n];} - } - hold.playbackGain = orig.playbackGain; - hold.lufs = orig.lufs; - this.audioObjects[i].buffer.buffer = hold; + var lengthDiff = length - ao.buffer.buffer.length; + ao.buffer = ao.buffer.copyBuffer(0,samplesToSeconds(lengthDiff,ao.buffer.buffer.sampleRate)); } }; @@ -1387,26 +1502,13 @@ this.buffer = callee; return; } - if (audioEngineContext.loopPlayback){ - // First copy the buffer into this.buffer - this.buffer = new audioEngineContext.bufferObj(); - this.buffer.url = callee.url; - this.buffer.buffer = audioContext.createBuffer(callee.buffer.numberOfChannels, callee.buffer.length, callee.buffer.sampleRate); - for (var c=0; c<callee.buffer.numberOfChannels; c++) - { - var src = callee.buffer.getChannelData(c); - var dst = this.buffer.buffer.getChannelData(c); - for (var n=0; n<src.length; n++) - { - dst[n] = src[n]; - } - } - } else { - this.buffer = callee; - } + this.buffer = callee; + var preSilenceTime = this.specification.preSilence || this.specification.parent.preSilence || specification.preSilence || 0.0; + var postSilenceTime = this.specification.postSilence || this.specification.parent.postSilence || specification.postSilence || 0.0; + if (preSilenceTime != 0 || postSilenceTime != 0) { + this.buffer = callee.copyBuffer(preSilenceTime,postSilenceTime); + } this.state = 1; - this.buffer.buffer.playbackGain = callee.buffer.playbackGain; - this.buffer.buffer.lufs = callee.buffer.lufs; var targetLUFS = this.specification.parent.loudness || specification.loudness; if (typeof targetLUFS === "number") { @@ -1763,34 +1865,6 @@ return storeDOM; }; } - -function randomiseOrder(input) -{ - // This takes an array of information and randomises the order - var N = input.length; - - var inputSequence = []; // For safety purposes: keep track of randomisation - for (var counter = 0; counter < N; ++counter) - inputSequence.push(counter) // Fill array - var inputSequenceClone = inputSequence.slice(0); - - var holdArr = []; - var outputSequence = []; - for (var n=0; n<N; n++) - { - // First pick a random number - var r = Math.random(); - // Multiply and floor by the number of elements left - r = Math.floor(r*input.length); - // Pick out that element and delete from the array - holdArr.push(input.splice(r,1)[0]); - // Do the same with sequence - outputSequence.push(inputSequence.splice(r,1)[0]); - } - console.log(inputSequenceClone.toString()); // print original array to console - console.log(outputSequence.toString()); // print randomised array to console - return holdArr; -} function Interface(specificationObject) { // This handles the bindings between the interface and the audioEngineContext;
--- a/example_eval/ABX_example.xml Wed Apr 13 16:20:56 2016 +0100 +++ b/example_eval/ABX_example.xml Thu Apr 14 13:20:58 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="ABX" projectReturn="save.php" randomiseOrder='true' testPages="2" loudness="-23" sampleRate="44100"> + <setup interface="ABX" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100"> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true"> <statement>Please enter your name.</statement>
--- a/example_eval/AB_example.xml Wed Apr 13 16:20:56 2016 +0100 +++ b/example_eval/AB_example.xml Thu Apr 14 13:20:58 2016 +0100 @@ -1,6 +1,6 @@ <?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' testPages="2" loudness="-23" sampleRate="44100"> + <setup interface="AB" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100"> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true"> <statement>Please enter your name.</statement>
--- a/example_eval/mushra_example.xml Wed Apr 13 16:20:56 2016 +0100 +++ b/example_eval/mushra_example.xml Thu Apr 14 13:20:58 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="MUSHRA" projectReturn="save.php" randomiseOrder='true' testPages="2" loudness="-23" sampleRate="44100"> + <setup interface="MUSHRA" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100"> <exitText>Thank you for looking at WAET. You can modify the successful completion text as well!</exitText> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true">
--- a/example_eval/project.xml Wed Apr 13 16:20:56 2016 +0100 +++ b/example_eval/project.xml Thu Apr 14 13:20:58 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="APE" projectReturn="save.php" randomiseOrder='true' testPages="2" loudness="-23" sampleRate="44100" calibration="true"> + <setup interface="APE" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100" calibration="true"> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true"> <statement>Please enter your name.</statement>
--- a/example_eval/radio_example.xml Wed Apr 13 16:20:56 2016 +0100 +++ b/example_eval/radio_example.xml Thu Apr 14 13:20:58 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" ?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="likert" projectReturn="save.php"> + <setup interface="likert" projectReturn="save.php" crossFade="3.0"> <metric> <metricenable>testTimer</metricenable> <metricenable>elementTimer</metricenable> @@ -18,7 +18,7 @@ <interfaceoption type="show" name="page-count"/> </interface> </setup> - <page id='test-0' hostURL="example_eval/" randomiseOrder='true' repeatCount='4' loop='true' showElementComments='true' loudness="-23"> + <page id='test-0' hostURL="example_eval/" randomiseOrder='true' repeatCount='4' loop='true' showElementComments='true' loudness="-23" poolSize="3"> <interface> <scales> <scalelabel position="0">(1) Very Annoying</scalelabel> @@ -28,8 +28,9 @@ <scalelabel position="100">(5) Inaudible</scalelabel> </scales> </interface> - <audioelement url="0.wav" id="track-1"/> + <audioelement url="0.wav" id="track-1" alwaysInclude="true"/> <audioelement url="1.wav" id="track-2"/> + <audioelement url="3.wav" id="track-4"/> <audioelement url="2.wav" id="track-3" type="outside-reference"/> </page> </waet>
--- a/scripts/pythonServer-3.py Wed Apr 13 16:20:56 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -from http.server import BaseHTTPRequestHandler, HTTPServer -from os import walk -from os import path -from os import listdir -import inspect -import os -import urllib as urllib2 -import pickle -import datetime - -# Go to right folder. -scriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory -os.chdir(scriptdir) # does this work? - -PSEUDO_PATH = 'example_eval/' -pseudo_files = [] -for filename in listdir(PSEUDO_PATH): - if filename.endswith('.xml'): - pseudo_files.append(filename) - -curSaveIndex = 0; -curFileName = 'test-0.xml' -while(path.isfile('saves/'+curFileName)): - curSaveIndex += 1; - curFileName = 'test-'+str(curSaveIndex)+'.xml' - -pseudo_index = curSaveIndex % len(pseudo_files) - -print('URL: http://localhost:8000/index.html') - -def send404(s): - s.send_response(404) - s.send_header("Content-type", "text/html") - s.end_headers() - -def processFile(s): - s.path = s.path.rsplit('?') - s.path = s.path[0] - s.path = s.path[1:len(s.path)] - st = s.path.rsplit(',') - lenSt = len(st) - fmt = st[lenSt-1].rsplit('.') - s.send_response(200) - if (fmt[1] == 'html'): - s.send_header("Content-type", 'text/html') - fileDump = open(urllib2.parse.unquote(s.path), encoding='utf-8') - fileBytes = bytes(fileDump.read(), "utf-8") - fileDump.close() - elif (fmt[1] == 'css'): - s.send_header("Content-type", 'text/css') - fileDump = open(urllib2.parse.unquote(s.path), encoding='utf-8') - fileBytes = bytes(fileDump.read(), "utf-8") - fileDump.close() - elif (fmt[1] == 'js'): - s.send_header("Content-type", 'application/javascript') - fileDump = open(urllib2.parse.unquote(s.path), encoding='utf-8') - fileBytes = bytes(fileDump.read(), "utf-8") - fileDump.close() - else: - s.send_header("Content-type", 'application/octet-stream') - fileDump = open(urllib2.parse.unquote(s.path), 'rb') - fileBytes = fileDump.read() - fileDump.close() - s.send_header("Content-Length", len(fileBytes)) - s.end_headers() - s.wfile.write(fileBytes) - -def saveFile(self): - global curFileName - global curSaveIndex - varLen = int(self.headers['Content-Length']) - postVars = self.rfile.read(varLen) - print(curFileName) - file = open('saves/'+curFileName,'w') - file.write(postVars.decode("utf-8")) - file.close() - try: - wbytes = os.path.getsize('saves/'+curFileName) - except OSError: - self.send_response(200) - self.send_header("Content-type", "text/xml") - self.end_headers() - self.wfile.write('<response state="error"><message>Could not open file</message></response>') - self.send_response(200) - self.send_header("Content-type", "text/xml") - self.end_headers() - self.wfile.write(bytes('<response state="OK"><message>OK</message><file bytes="'+str(wbytes)+'">"saves/'+curFileName+'"</file></response>','utf-8')) - curSaveIndex += 1 - curFileName = 'test-'+str(curSaveIndex)+'.xml' - -class MyHandler(BaseHTTPRequestHandler): - def do_HEAD(s): - s.send_response(200) - s.send_header("Content-type", "text/html") - s.end_headers() - def do_GET(request): - global pseudo_index - global pseudo_files - global PSEUDO_PATH - if(request.client_address[0] == "127.0.0.1"): - if (request.path == "/favicon.ico"): - send404(request) - else: - if (request.path == '/'): - request.path = '/index.html' - elif (request.path == '/pseudo.xml'): - request.path = '/'+PSEUDO_PATH + pseudo_files[pseudo_index] - print(request.path) - pseudo_index += 1 - pseudo_index %= len(pseudo_files) - processFile(request) - else: - send404(request) - - def do_POST(request): - if(request.client_address[0] == "127.0.0.1"): - if (request.path == "/save" or request.path == "/save.php"): - saveFile(request) - else: - send404(request) - -def run(server_class=HTTPServer, - handler_class=MyHandler): - server_address = ('', 8000) - httpd = server_class(server_address, handler_class) - httpd.serve_forever() - -run()
--- a/scripts/pythonServer-legacy.py Wed Apr 13 16:20:56 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -import SimpleHTTPServer -import SocketServer - -PORT = 8080 - -Handler = SimpleHTTPServer.SimpleHTTPRequestHandler - -httpd = SocketServer.TCPServer(("", PORT), Handler) - -print "serving at port", PORT -httpd.serve_forever()
--- a/scripts/pythonServer.py Wed Apr 13 16:20:56 2016 +0100 +++ b/scripts/pythonServer.py Thu Apr 14 13:20:58 2016 +0100 @@ -1,21 +1,32 @@ #!/usr/bin/python -import BaseHTTPServer +# Detect the Python version to switch code between 2.x and 3.x +# http://stackoverflow.com/questions/9079036/detect-python-version-at-runtime +import sys + from os import walk from os import path from os import listdir import inspect import os -import urllib2 -import urlparse import pickle import datetime +if sys.version_info[0] == 2: + # Version 2.x + import BaseHTTPServer + import urllib2 + import urlparse +elif sys.version_info[0] == 3: + # Version 3.x + from http.server import BaseHTTPRequestHandler, HTTPServer + import urllib as urllib2 + # Go to right folder. scriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory os.chdir(scriptdir) # does this work? -PSEUDO_PATH = 'example_eval/' +PSEUDO_PATH = '../example_eval/' pseudo_files = [] for filename in listdir(PSEUDO_PATH): if filename.endswith('.xml'): @@ -23,42 +34,79 @@ curSaveIndex = 0; curFileName = 'test-0.xml' -while(path.isfile('saves/'+curFileName)): - curSaveIndex += 1; - curFileName = 'test-'+str(curSaveIndex)+'.xml' +while(path.isfile('../saves/'+curFileName)): + curSaveIndex += 1; + curFileName = 'test-'+str(curSaveIndex)+'.xml' pseudo_index = curSaveIndex % len(pseudo_files) -print 'URL: http://localhost:8000/index.html' +if sys.version_info[0] == 2: + print 'URL: http://localhost:8000/index.html' +elif sys.version_info[0] == 3: + print('URL: http://localhost:8000/index.html') def send404(s): - s.send_response(404) - s.send_header("Content-type", "text/html") - s.end_headers() + s.send_response(404) + s.send_header("Content-type", "text/html") + s.end_headers() def processFile(s): - s.path = s.path.rsplit('?') - s.path = s.path[0] - s.path = s.path[1:len(s.path)] - st = s.path.rsplit(',') - lenSt = len(st) - fmt = st[lenSt-1].rsplit('.') - size = path.getsize(urllib2.unquote(s.path)) - fileDump = open(urllib2.unquote(s.path)) - s.send_response(200) - - if (fmt[1] == 'html'): - s.send_header("Content-type", 'text/html') - elif (fmt[1] == 'css'): - s.send_header("Content-type", 'text/css') - elif (fmt[1] == 'js'): - s.send_header("Content-type", 'application/javascript') - else: - s.send_header("Content-type", 'application/octet-stream') - s.send_header("Content-Length", size) - s.end_headers() - s.wfile.write(fileDump.read()) - fileDump.close() + if sys.version_info[0] == 2: + s.path = s.path.rsplit('?') + s.path = s.path[0] + s.path = s.path[1:len(s.path)] + st = s.path.rsplit(',') + lenSt = len(st) + fmt = st[lenSt-1].rsplit('.') + fpath = "../"+urllib2.unquote(s.path) + size = path.getsize(fpath) + fileDump = open(fpath) + s.send_response(200) + + if (fmt[1] == 'html'): + s.send_header("Content-type", 'text/html') + elif (fmt[1] == 'css'): + s.send_header("Content-type", 'text/css') + elif (fmt[1] == 'js'): + s.send_header("Content-type", 'application/javascript') + else: + s.send_header("Content-type", 'application/octet-stream') + s.send_header("Content-Length", size) + s.end_headers() + s.wfile.write(fileDump.read()) + fileDump.close() + elif sys.version_info[0] == 3: + s.path = s.path.rsplit('?') + s.path = s.path[0] + s.path = s.path[1:len(s.path)] + st = s.path.rsplit(',') + lenSt = len(st) + fmt = st[lenSt-1].rsplit('.') + fpath = "../"+urllib2.unquote(s.path) + s.send_response(200) + if (fmt[1] == 'html'): + s.send_header("Content-type", 'text/html') + fileDump = open(fpath, encoding='utf-8') + fileBytes = bytes(fileDump.read(), "utf-8") + fileDump.close() + elif (fmt[1] == 'css'): + s.send_header("Content-type", 'text/css') + fileDump = open(fpath, encoding='utf-8') + fileBytes = bytes(fileDump.read(), "utf-8") + fileDump.close() + elif (fmt[1] == 'js'): + s.send_header("Content-type", 'application/javascript') + fileDump = open(fpath, encoding='utf-8') + fileBytes = bytes(fileDump.read(), "utf-8") + fileDump.close() + else: + s.send_header("Content-type", 'application/octet-stream') + fileDump = open(fpath, 'rb') + fileBytes = fileDump.read() + fileDump.close() + s.send_header("Content-Length", len(fileBytes)) + s.end_headers() + s.wfile.write(fileBytes) def keygen(s): reply = "" @@ -74,36 +122,39 @@ s.send_header("Content-type", "application/xml") s.end_headers() s.wfile.write(reply) - file = open("saves/save-"+key+".xml",'w') + file = open("../saves/save-"+key+".xml",'w') file.write("<waetresult key="+key+"/>") file.close(); def saveFile(self): - global curFileName - global curSaveIndex - options = self.path.rsplit('?') - options = options[1].rsplit('=') - key = options[1] - print key - varLen = int(self.headers['Content-Length']) - postVars = self.rfile.read(varLen) - print "Saving file key "+key - file = open('saves/save-'+key+'.xml','w') - file.write(postVars) - file.close() - try: - wbytes = os.path.getsize('saves/save-'+key+'.xml') - except OSError: - self.send_response(200) - self.send_header("Content-type", "text/xml") - self.end_headers() - self.wfile.write('<response state="error"><message>Could not open file</message></response>') - self.send_response(200) - self.send_header("Content-type", "text/xml") - self.end_headers() - self.wfile.write('<response state="OK"><message>OK</message><file bytes="'+str(wbytes)+'">"saves/'+curFileName+'"</file></response>') - curSaveIndex += 1 - curFileName = 'test-'+str(curSaveIndex)+'.xml' + global curFileName + global curSaveIndex + options = self.path.rsplit('?') + options = options[1].rsplit('=') + key = options[1] + print key + varLen = int(self.headers['Content-Length']) + postVars = self.rfile.read(varLen) + if sys.version_info[0] == 2: + print "Saving file key "+key + elif sys.version_info[0] == 3: + print("Saving file key "+key) + file = open('../saves/save-'+key+'.xml','w') + file.write(postVars) + file.close() + try: + wbytes = os.path.getsize('../saves/save-'+key+'.xml') + except OSError: + self.send_response(200) + self.send_header("Content-type", "text/xml") + self.end_headers() + self.wfile.write('<response state="error"><message>Could not open file</message></response>') + self.send_response(200) + self.send_header("Content-type", "text/xml") + self.end_headers() + self.wfile.write('<response state="OK"><message>OK</message><file bytes="'+str(wbytes)+'">"saves/'+curFileName+'"</file></response>') + curSaveIndex += 1 + curFileName = 'test-'+str(curSaveIndex)+'.xml' class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_HEAD(s): @@ -137,11 +188,15 @@ saveFile(request) else: send404(request) - -def run(server_class=BaseHTTPServer.HTTPServer, - handler_class=MyHandler): - server_address = ('', 8000) - httpd = server_class(server_address, handler_class) - httpd.serve_forever() +if sys.version_info[0] == 2: + def run(server_class=BaseHTTPServer.HTTPServer,handler_class=MyHandler): + server_address = ('', 8000) + httpd = server_class(server_address, handler_class) + httpd.serve_forever() +elif sys.version_info[0] == 3: + def run(server_class=HTTPServer,handler_class=MyHandler): + server_address = ('', 8000) + httpd = server_class(server_address, handler_class) + httpd.serve_forever() run()
--- a/specification.js Wed Apr 13 16:20:56 2016 +0100 +++ b/specification.js Thu Apr 14 13:20:58 2016 +0100 @@ -27,7 +27,19 @@ } var dataType = schema.getAttribute('type'); if (typeof dataType == "string") { dataType = dataType.substr(3);} - else {dataType = "string";} + else { + var rest = schema.getAllElementsByTagName("xs:restriction").concat(schema.getAllElementsByTagName("xs:enumeration")); + if (rest.length > 0) { + dataType = rest[0].getAttribute("base"); + if (typeof dataType == "string") { + dataType = dataType.substr(3); + } else { + dataType = "string"; + } + } else { + dataType = "string"; + } + } if (attribute == null) { return attribute;
--- a/test-schema.xsd Wed Apr 13 16:20:56 2016 +0100 +++ b/test-schema.xsd Thu Apr 14 13:20:58 2016 +0100 @@ -1,263 +1,275 @@ <?xml version="1.0"?> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <!-- define simple elements--> - <xs:element name="statement" type="xs:string"/> - <xs:element name="metricenable" type="xs:string"/> - <xs:element name="title" type="xs:string"/> - - <!-- define simple attributes--> - <xs:attribute name="id" type="xs:ID"/> - <xs:attribute name="mandatory" type="xs:boolean"/> - <xs:attribute name="name" type="xs:string"/> + <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <!-- define simple elements--> + <xs:element name="statement" type="xs:string" /> + <xs:element name="metricenable" type="xs:string" /> + <xs:element name="title" type="xs:string" /> - <xs:attribute name="preSilence" default="0"> - <xs:simpleType> - <xs:restriction base="xs:decimal"> - <xs:minInclusive value="0.0"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="postSilence" default="0"> - <xs:simpleType> - <xs:restriction base="xs:decimal"> - <xs:minInclusive value="0.0"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - - <!-- define complex elements--> - <xs:element name="waet"> - <xs:complexType> - <xs:sequence> - <xs:element ref="setup" minOccurs="1" maxOccurs="1"/> - <xs:element ref="page" minOccurs="1" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - </xs:element> + <!-- define simple attributes--> + <xs:attribute name="id" type="xs:ID" /> + <xs:attribute name="mandatory" type="xs:boolean" /> + <xs:attribute name="name" type="xs:string" /> + <xs:attribute name="poolSize" type="xs:nonNegativeInteger" default="0" /> + <xs:attribute name="alwaysInclude" type="xs:boolean" default="false" /> - <xs:element name="setup"> - <xs:complexType> - <xs:sequence> - <xs:element name="exitText" type="xs:string" minOccurs="0" maxOccurs="1"/> - <xs:element ref="survey" minOccurs="0" maxOccurs="2"/> - <xs:element ref="metric" maxOccurs="1"/> - <xs:element ref="interface" maxOccurs="1"/> - </xs:sequence> - <xs:attribute name="interface" type="xs:string" use="required"/> - <xs:attribute name="projectReturn" type="xs:string" use="optional" default=""/> - <xs:attribute name="randomiseOrder" type="xs:boolean" default="false"/> - <xs:attribute name="testPages" type="xs:nonNegativeInteger" default="0"/> - <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional"/> - <xs:attribute name="sampleRate" type="xs:positiveInteger" use="optional"/> - <xs:attribute name="calibration" type="xs:boolean" default="false"/> - <xs:attribute ref="preSilence"/> - <xs:attribute ref="postSilence"/> - </xs:complexType> - </xs:element> + <xs:attribute name="preSilence"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.0" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="postSilence"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.0" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> - <xs:element name="page"> - <xs:complexType> - <xs:sequence> - <xs:element ref="title" minOccurs="0" maxOccurs="1"/> - <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="survey" minOccurs="0" maxOccurs="2"/> - </xs:sequence> - <xs:attribute ref="id" use="required"/> - <xs:attribute name="hostURL" type="xs:anyURI" default=""/> - <xs:attribute name="randomiseOrder" type="xs:boolean" default="false"/> - <xs:attribute name="repeatCount" type="xs:nonNegativeInteger" default="0"/> - <xs:attribute name="loop" type="xs:boolean" default="false"/> - <xs:attribute name="showElementComments" type="xs:boolean" default="false"/> - <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional"/> - <xs:attribute name="label" use="optional" default="default"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="default"/> - <xs:enumeration value="none"/> - <xs:enumeration value="number"/> - <xs:enumeration value="letter"/> - <xs:enumeration value="capital"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute ref="preSilence"/> - <xs:attribute ref="postSilence"/> - </xs:complexType> - </xs:element> + <!-- define complex elements--> + <xs:element name="waet"> + <xs:complexType> + <xs:sequence> + <xs:element ref="setup" minOccurs="1" maxOccurs="1" /> + <xs:element ref="page" minOccurs="1" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + </xs:element> - <xs:element name="metric"> - <xs:complexType> - <xs:sequence> - <xs:element name="metricenable" type="xs:string" minOccurs="0" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - </xs:element> + <xs:element name="setup"> + <xs:complexType> + <xs:sequence> + <xs:element name="exitText" type="xs:string" minOccurs="0" maxOccurs="1" /> + <xs:element ref="survey" minOccurs="0" maxOccurs="2" /> + <xs:element ref="metric" maxOccurs="1" /> + <xs:element ref="interface" maxOccurs="1" /> + </xs:sequence> + <xs:attribute name="interface" type="xs:string" use="required" /> + <xs:attribute name="projectReturn" type="xs:string" use="optional" default="" /> + <xs:attribute name="randomiseOrder" type="xs:boolean" default="false" /> + <xs:attribute ref="poolSize" /> + <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional" /> + <xs:attribute name="sampleRate" type="xs:positiveInteger" use="optional" /> + <xs:attribute name="calibration" type="xs:boolean" default="false" /> + <xs:attribute name="crossFade" default="0.0"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.0" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute ref="preSilence" /> + <xs:attribute ref="postSilence" /> + </xs:complexType> + </xs:element> - <xs:element name="interface"> - <xs:complexType> - <xs:sequence> - <xs:element ref="title" minOccurs="0" maxOccurs="1"/> - <xs:element name="interfaceoption" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:attribute name="type" use="required"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="check"/> - <xs:enumeration value="show"/> - <xs:enumeration value="option"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute ref="name" use="required"/> - <xs:attribute name="min" type="xs:decimal" use="optional"/> - <xs:attribute name="max" type="xs:decimal" use="optional"/> - </xs:complexType> + <xs:element name="page"> + <xs:complexType> + <xs:sequence> + <xs:element ref="title" minOccurs="0" maxOccurs="1" /> + <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="survey" minOccurs="0" maxOccurs="2" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute name="hostURL" type="xs:anyURI" default="" /> + <xs:attribute name="randomiseOrder" type="xs:boolean" default="false" /> + <xs:attribute name="repeatCount" type="xs:nonNegativeInteger" default="0" /> + <xs:attribute name="loop" type="xs:boolean" default="false" /> + <xs:attribute name="showElementComments" type="xs:boolean" default="false" /> + <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional" /> + <xs:attribute name="label" use="optional" default="default"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="default" /> + <xs:enumeration value="none" /> + <xs:enumeration value="number" /> + <xs:enumeration value="letter" /> + <xs:enumeration value="capital" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute ref="poolSize" /> + <xs:attribute ref="alwaysInclude" /> + <xs:attribute ref="preSilence" /> + <xs:attribute ref="postSilence" /> + </xs:complexType> </xs:element> - <xs:element name="scales" minOccurs="0" maxOccurs="1"> - <xs:complexType> - <xs:sequence> - <xs:element name="scalelabel" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute name="position" use="required"> - <xs:simpleType> - <xs:restriction base="xs:nonNegativeInteger"> - <xs:minInclusive value="0"/> - <xs:maxInclusive value="100"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> + + <xs:element name="metric"> + <xs:complexType> + <xs:sequence> + <xs:element name="metricenable" type="xs:string" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> </xs:element> - </xs:sequence> - <xs:attribute ref="name" use="optional"/> - </xs:complexType> - </xs:element> - <xs:element name="audioelement"> - <xs:complexType> - <xs:attribute ref="id" use="required"/> - <xs:attribute name="url" type="xs:anyURI" use="required"/> - <xs:attribute name="gain" type="xs:decimal" default="0"/> - <xs:attribute ref="name"/> - <xs:attribute name="type" default="normal"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="normal"/> - <xs:enumeration value="anchor"/> - <xs:enumeration value="reference"/> - <xs:enumeration value="outside-reference"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="marker" use="optional"> - <xs:simpleType> - <xs:restriction base="xs:nonNegativeInteger"> - <xs:minInclusive value="0"/> - <xs:maxInclusive value="100"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional"/> - <xs:attribute ref="preSilence"/> - <xs:attribute ref="postSilence"/> - </xs:complexType> - </xs:element> + <xs:element name="interface"> + <xs:complexType> + <xs:sequence> + <xs:element ref="title" minOccurs="0" maxOccurs="1" /> + <xs:element name="interfaceoption" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="type" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="check" /> + <xs:enumeration value="show" /> + <xs:enumeration value="option" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute ref="name" use="required" /> + <xs:attribute name="min" type="xs:decimal" use="optional" /> + <xs:attribute name="max" type="xs:decimal" use="optional" /> + </xs:complexType> + </xs:element> + <xs:element name="scales" minOccurs="0" maxOccurs="1"> + <xs:complexType> + <xs:sequence> + <xs:element name="scalelabel" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="position" use="required"> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="100" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute ref="name" use="optional" /> + </xs:complexType> + </xs:element> - <xs:element name="commentquestion"> - <xs:complexType> - <xs:sequence> - <xs:element ref="statement" minOccurs="0" 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 name="audioelement"> + <xs:complexType> + <xs:attribute ref="id" use="required" /> + <xs:attribute name="url" type="xs:anyURI" use="required" /> + <xs:attribute name="gain" type="xs:decimal" default="0" /> + <xs:attribute ref="name" /> + <xs:attribute name="type" default="normal"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="normal" /> + <xs:enumeration value="anchor" /> + <xs:enumeration value="reference" /> + <xs:enumeration value="outside-reference" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="marker" use="optional"> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="100" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional" /> + <xs:attribute ref="alwaysInclude" /> + <xs:attribute ref="preSilence" /> + <xs:attribute ref="postSilence" /> + </xs:complexType> </xs:element> - </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="survey"> - <xs:complexType> - <xs:sequence> - <xs:element name="surveyentry" minOccurs="0" maxOccurs="unbounded"> - <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="required"/> - <xs:attribute ref="name"/> - <xs:attribute ref="mandatory"/> - <xs:attribute name="min" type="xs:decimal"/> - <xs:attribute name="max" type="xs:decimal"/> - <xs:attribute name="type" use="required"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="statement"/> - <xs:enumeration value="question"/> - <xs:enumeration value="number"/> - <xs:enumeration value="radio"/> - <xs:enumeration value="checkbox"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="boxsize" default="normal"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="normal"/> - <xs:enumeration value="large"/> - <xs:enumeration value="small"/> - <xs:enumeration value="huge"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:complexType> + <xs:element name="commentquestion"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="0" 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: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:sequence> - <xs:attribute name="location"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="before"/> - <xs:enumeration value="pre"/> - <xs:enumeration value="after"/> - <xs:enumeration value="post"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:complexType> - </xs:element> - -</xs:schema> \ No newline at end of file + + <xs:element name="survey"> + <xs:complexType> + <xs:sequence> + <xs:element name="surveyentry" minOccurs="0" maxOccurs="unbounded"> + <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="required" /> + <xs:attribute ref="name" /> + <xs:attribute ref="mandatory" /> + <xs:attribute name="min" type="xs:decimal" /> + <xs:attribute name="max" type="xs:decimal" /> + <xs:attribute name="type" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="statement" /> + <xs:enumeration value="question" /> + <xs:enumeration value="number" /> + <xs:enumeration value="radio" /> + <xs:enumeration value="checkbox" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="boxsize" default="normal"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="normal" /> + <xs:enumeration value="large" /> + <xs:enumeration value="small" /> + <xs:enumeration value="huge" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="location"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="before" /> + <xs:enumeration value="pre" /> + <xs:enumeration value="after" /> + <xs:enumeration value="post" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> + </xs:element> + + </xs:schema>