qti 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +9 -1
  3. data/lib/qti/v1/models/assessment.rb +2 -2
  4. data/lib/qti/v1/models/assessment_item.rb +5 -29
  5. data/lib/qti/v1/models/interactions/base_interaction.rb +33 -0
  6. data/lib/qti/v1/models/interactions/choice_interaction.rb +44 -0
  7. data/lib/qti/v1/models/interactions/match_interaction.rb +60 -0
  8. data/lib/qti/v1/models/interactions/ordering_interaction.rb +23 -0
  9. data/lib/qti/v1/models/interactions/string_interaction.rb +1 -3
  10. data/lib/qti/v1/models/interactions.rb +1 -3
  11. data/lib/qti/v1/models/scoring_data.rb +7 -0
  12. data/lib/qti/v2/models/assessment_item.rb +2 -6
  13. data/lib/qti/v2/models/choices/simple_associable_choice.rb +12 -0
  14. data/lib/qti/v2/models/interactions/base_interaction.rb +43 -0
  15. data/lib/qti/v2/models/interactions/choice_interaction.rb +2 -12
  16. data/lib/qti/v2/models/interactions/extended_text_interaction.rb +1 -5
  17. data/lib/qti/v2/models/interactions/match_interaction.rb +52 -0
  18. data/lib/qti/v2/models/scoring_data.rb +7 -0
  19. data/lib/qti.rb +6 -0
  20. data/spec/fixtures/items_1.2/matching.xml +74 -0
  21. data/spec/fixtures/items_1.2/multiple_answer.xml +1 -1
  22. data/spec/fixtures/items_1.2/multiple_choice.xml +1 -1
  23. data/spec/fixtures/items_1.2/ordering.xml +20 -20
  24. data/spec/fixtures/items_1.2/true_false.xml +1 -1
  25. data/spec/fixtures/items_2.1/match.xml +33 -39
  26. data/spec/fixtures/test_qti_1.2/quiz.xml +209 -216
  27. data/spec/lib/qti/v1/models/assessment_item_spec.rb +20 -2
  28. data/spec/lib/qti/v1/models/interactions/{logical_identifier_interaction_spec.rb → choice_interaction_spec.rb} +1 -1
  29. data/spec/lib/qti/v2/models/assessment_item_spec.rb +24 -0
  30. metadata +15 -5
  31. data/lib/qti/v1/models/interactions/logical_identifier_interaction.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4276f67d46173a7c7059c36687cf77c930a0bb36
4
- data.tar.gz: 05b05ab5d7c63ce1bcb12ae3a8a688eb30d491c3
3
+ metadata.gz: 7e3dbac8ff4eda0f1c6f67c6f8e7e1673ac8014b
4
+ data.tar.gz: 807c9a6be3ea4e1887966bb5734015dc017efa04
5
5
  SHA512:
6
- metadata.gz: 10314c5ed21040925853f8b98e1e07f222d3a8921ce44875f26962dafbf43cfc8480b32523653d0161d1dcffe00573e038415ef4fff2d7956341322e3c1d530d
7
- data.tar.gz: 372d29818743f5f26d26db7b2a02d995e68f4f73a7022fff9a7691584b39631a30c0f2b74110f5b39d7c4e7b3fa41816351ac444e92792e3885a7408d4b3e11d
6
+ metadata.gz: a628c8aa5c49fdea190b112136ab3ad22861725437b7c167c2ac6188ae7970a5641a6d794243726d4b9c24c0986ad33900d22816a4576fa056e5acc50c328db8
7
+ data.tar.gz: 1a92b8176ca835e95923c936ae5c86b77c60e9ba702c7f6dd0d84d082c1ae6aa6eb63a670681bbfb34bb54ada67391c2ab394f4d6182f631712bf57b5376e83f
data/Rakefile CHANGED
@@ -1 +1,9 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+
3
+ desc 'Initialize console'
4
+ task :console do
5
+ require 'pry'
6
+ require 'qti'
7
+ ARGV.clear
8
+ Pry.start
9
+ end
@@ -5,11 +5,11 @@ module Qti
5
5
  module Models
6
6
  class Assessment < Qti::V1::Models::Base
7
7
  def title
8
- @title ||= xpath_with_single_check('//assessment/@title').content
8
+ @title ||= xpath_with_single_check('.//xmlns:assessment/@title')&.content
9
9
  end
10
10
 
11
11
  def assessment_items
12
- @doc.xpath('//item')
12
+ @doc.xpath('.//xmlns:item')
13
13
  end
14
14
  end
15
15
  end
@@ -7,8 +7,6 @@ module Qti
7
7
  class AssessmentItem < Qti::V1::Models::Base
8
8
  attr_reader :doc
9
9
 
10
- ScoringData = Struct.new(:values, :rcardinality)
11
-
12
10
  def initialize(item)
13
11
  @doc = item
14
12
  end
@@ -16,8 +14,8 @@ module Qti
16
14
  def item_body
17
15
  @item_body ||= begin
18
16
  node = @doc.dup
19
- presentation = node.at_xpath('./presentation')
20
- prompt = presentation.at_xpath('//material/mattext').content
17
+ presentation = node.at_xpath('.//xmlns:presentation')
18
+ prompt = presentation.at_xpath('.//xmlns:mattext').content
21
19
  sanitize_content!(prompt)
22
20
  end
23
21
  end
@@ -32,12 +30,12 @@ module Qti
32
30
 
33
31
  def points_possible
34
32
  @points_possible ||= begin
35
- @doc.at_xpath('.//decvar/@maxvalue')&.value || @doc.at_xpath('.//decvar/@defaultval')&.value
33
+ @doc.at_xpath('.//xmlns:decvar/@maxvalue')&.value || @doc.at_xpath('.//xmlns:decvar/@defaultval')&.value
36
34
  end
37
35
  end
38
36
 
39
37
  def rcardinality
40
- @rcardinality ||= @doc.at_xpath('.//response_lid/@rcardinality').value
38
+ @rcardinality ||= @doc.at_xpath('.//xmlns:response_lid/@rcardinality').value
41
39
  end
42
40
 
43
41
  def interaction_model
@@ -47,29 +45,7 @@ module Qti
47
45
  end
48
46
 
49
47
  def scoring_data_structs
50
- @scoring_data_structs ||=
51
- if ordering?
52
- scoring_data_structs_for_ordering
53
- else
54
- default_scoring_data_structs
55
- end
56
- end
57
-
58
- private
59
-
60
- def default_scoring_data_structs
61
- choice_nodes = doc.xpath('.//respcondition')
62
- choice_nodes.select { |choice_node| choice_node.at_xpath('.//setvar').content.to_f.positive? }
63
- .map { |value_node| ScoringData.new(value_node.at_xpath('.//varequal').content, rcardinality) }
64
- end
65
-
66
- def scoring_data_structs_for_ordering
67
- correct_order = @doc.xpath('.//conditionvar/varequal').map{|node| node.content }
68
- [ScoringData.new(correct_order, rcardinality)]
69
- end
70
-
71
- def ordering?
72
- rcardinality == 'Ordered'
48
+ @scoring_data_structs ||= interaction_model.scoring_data_structs
73
49
  end
74
50
  end
75
51
  end
@@ -0,0 +1,33 @@
1
+ module Qti
2
+ module V1
3
+ module Models
4
+ module Interactions
5
+ class BaseInteraction < Qti::V1::Models::Base
6
+ attr_reader :node
7
+
8
+ def self.matches(node)
9
+ false
10
+ end
11
+
12
+ def initialize(node)
13
+ @node = node
14
+ end
15
+
16
+ def shuffled?
17
+ @node.at_xpath('.//xmlns:render_choice/@shuffle')&.value == 'Yes'
18
+ end
19
+
20
+ def scoring_data_structs
21
+ raise NotImplementedError
22
+ end
23
+
24
+ private
25
+
26
+ def rcardinality
27
+ @rcardinality ||= @node.at_xpath('.//xmlns:response_lid/@rcardinality').value
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ module Qti
2
+ module V1
3
+ module Models
4
+ module Interactions
5
+ class ChoiceInteraction < BaseInteraction
6
+ # This will know if a class matches
7
+ def self.matches(node)
8
+ matches = node.xpath('.//xmlns:response_lid')
9
+ return false if matches.count > 1 || matches.empty?
10
+ rcardinality = matches.first.attributes['rcardinality']&.value || 'Single'
11
+ return false if rcardinality == 'Ordered'
12
+ new(node)
13
+ end
14
+
15
+ def initialize(node)
16
+ @node = node
17
+ end
18
+
19
+ def shuffled?
20
+ node.at_xpath('.//xmlns:render_choice/@shuffle')&.value == 'Yes'
21
+ end
22
+
23
+ def answers
24
+ @answers ||= answer_nodes.map do |node|
25
+ V1::Models::Choices::LogicalIdentifierChoice.new(node)
26
+ end
27
+ end
28
+
29
+ def scoring_data_structs
30
+ choice_nodes = node.xpath('.//xmlns:respcondition')
31
+ set_var_nodes = choice_nodes.select { |choice_node| choice_node.at_xpath('.//xmlns:setvar').content.to_f.positive? }
32
+ set_var_nodes.map { |value_node| ScoringData.new(value_node.at_xpath('.//xmlns:varequal').content, rcardinality) }
33
+ end
34
+
35
+ private
36
+
37
+ def answer_nodes
38
+ node.xpath('.//xmlns:response_label')
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,60 @@
1
+ module Qti
2
+ module V1
3
+ module Models
4
+ module Interactions
5
+ class MatchInteraction < BaseInteraction
6
+ attr_reader :node
7
+
8
+ def self.matches(node)
9
+ matches = node.xpath('.//xmlns:response_lid')
10
+ return false if matches.count <= 1
11
+ new(node)
12
+ end
13
+
14
+ def initialize(node)
15
+ @node = node
16
+ end
17
+
18
+ def answers
19
+ @answers ||= answer_nodes.map do |node|
20
+ V1::Models::Choices::LogicalIdentifierChoice.new(node)
21
+ end
22
+ end
23
+
24
+ def questions
25
+ node.xpath('.//xmlns:response_lid').map do |lid_node|
26
+ question_body = lid_node.at_xpath('.//xmlns:mattext').text
27
+ { id: lid_node.attributes['ident'].value, question_body: question_body }
28
+ end
29
+ end
30
+
31
+ def scoring_data_structs
32
+ matches = node.xpath('.//xmlns:varequal').map do |node|
33
+ [node.attributes['respident'].value, answers_map[node.content]]
34
+ end
35
+ [Models::ScoringData.new(Hash[matches], rcardinality)]
36
+ end
37
+
38
+ private
39
+
40
+ def answers_map
41
+ @answers_map ||= answers.reduce({}) do |acc, answer|
42
+ acc.update answer.identifier => answer.item_body
43
+ end
44
+ end
45
+
46
+ def answer_nodes
47
+ responses = []
48
+ response_ids = {}
49
+ node.xpath('.//xmlns:response_label').each do |answer_node|
50
+ ident = answer_node.attributes['ident'].value
51
+ responses << answer_node unless response_ids.key? ident
52
+ response_ids[ident] = 1
53
+ end
54
+ responses
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,23 @@
1
+ module Qti
2
+ module V1
3
+ module Models
4
+ module Interactions
5
+ class OrderingInteraction < ChoiceInteraction
6
+ # This will know if a class matches
7
+ def self.matches(node)
8
+ matches = node.xpath('.//xmlns:response_lid')
9
+ return false if matches.count > 1 || matches.empty?
10
+ rcardinality = matches.first.attributes['rcardinality']&.value || 'Single'
11
+ return false if rcardinality != 'Ordered'
12
+ new(node)
13
+ end
14
+
15
+ def scoring_data_structs
16
+ correct_order = node.xpath('.//xmlns:varequal').map(&:content)
17
+ [ScoringData.new(correct_order, rcardinality)]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,14 +2,12 @@ module Qti
2
2
  module V1
3
3
  module Models
4
4
  module Interactions
5
- class StringInteraction < Qti::V1::Models::Base
5
+ class StringInteraction < BaseInteraction
6
6
  @node_name = 'response_str'.freeze
7
7
  # This will know if a class matches
8
8
  def self.matches(node)
9
9
  matches = node.children.children.select { |n| n.name == @node_name }
10
10
  return false if matches.empty?
11
-
12
- raise Qti::UnsupportedSchema if matches.size > 1
13
11
  new(matches.first)
14
12
  end
15
13
 
@@ -14,9 +14,7 @@ module Qti
14
14
  match = interaction_class.matches(node)
15
15
  result << match if match
16
16
  end
17
-
18
- raise UnsupportedSchema if matches.size > 1
19
-
17
+ raise UnsupportedSchema if matches.size != 1
20
18
  matches.first
21
19
  end
22
20
  end
@@ -0,0 +1,7 @@
1
+ module Qti
2
+ module V1
3
+ module Models
4
+ ScoringData = Struct.new(:values, :rcardinality)
5
+ end
6
+ end
7
+ end
@@ -39,16 +39,12 @@ module Qti
39
39
 
40
40
  def interaction_model
41
41
  @interaction_model ||= begin
42
- V2::Models::Interactions.interaction_model(item_body_node)
42
+ V2::Models::Interactions.interaction_model(@doc)
43
43
  end
44
44
  end
45
45
 
46
46
  def scoring_data_structs
47
- @scoring_data_structs ||= begin
48
- type = xpath_with_single_check('//xmlns:responseDeclaration/@baseType').content
49
- value_nodes = @doc.xpath('//xmlns:responseDeclaration/xmlns:correctResponse/xmlns:value')
50
- value_nodes.map { |value_node| ScoringData.new(value_node.content, type) }
51
- end
47
+ @scoring_data_structs ||= interaction_model.scoring_data_structs
52
48
  end
53
49
 
54
50
  private
@@ -0,0 +1,12 @@
1
+ require 'qti/v2/models/base'
2
+
3
+ module Qti
4
+ module V2
5
+ module Models
6
+ module Choices
7
+ class SimpleAssociableChoice < SimpleChoice
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,43 @@
1
+ module Qti
2
+ module V2
3
+ module Models
4
+ module Interactions
5
+ class BaseInteraction < Qti::V2::Models::Base
6
+ attr_reader :node
7
+
8
+ def self.matches(node)
9
+ false
10
+ end
11
+
12
+ def initialize(node)
13
+ @node = node
14
+ end
15
+
16
+ def shuffled?
17
+ @node.at_xpath('.//render_choice/@shuffle')&.value == 'Yes'
18
+ end
19
+
20
+ def scoring_data_structs
21
+ @scoring_data_structs ||= begin
22
+ type = xpath_with_single_check('//xmlns:responseDeclaration/@baseType').content
23
+ value_nodes = node.xpath('//xmlns:responseDeclaration/xmlns:correctResponse/xmlns:value')
24
+ value_nodes.map { |value_node| Models::ScoringData.new(value_node.content, type) }
25
+ end
26
+ end
27
+
28
+ def xpath_with_single_check(xpath)
29
+ node_list = node.xpath(xpath)
30
+ raise Qti::ParseError, 'Too many matches' if node_list.count > 1
31
+ node_list.first
32
+ end
33
+
34
+ private
35
+
36
+ def rcardinality
37
+ @rcardinality ||= @node.at_xpath('.//response_lid/@rcardinality').value
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -2,25 +2,15 @@ module Qti
2
2
  module V2
3
3
  module Models
4
4
  module Interactions
5
- class ChoiceInteraction < Qti::V2::Models::Base
6
- @node_name = 'choiceInteraction'.freeze
7
- # This will know if a class matches
5
+ class ChoiceInteraction < BaseInteraction
8
6
  def self.matches(node)
9
- matches = node.children.filter(INTERACTION_ELEMENTS_CSS).select { |n| n.name == @node_name }
7
+ matches = node.xpath('.//xmlns:choiceInteraction')
10
8
  return false if matches.empty?
11
9
 
12
10
  raise Qti::UnsupportedSchema if matches.size > 1
13
11
  new(matches.first)
14
12
  end
15
13
 
16
- def initialize(node)
17
- @node = node
18
- end
19
-
20
- def shuffled?
21
- @node.attributes['shuffle'].value == 'true'
22
- end
23
-
24
14
  def answers
25
15
  @answers ||= answer_nodes.map do |node|
26
16
  V2::Models::Choices::SimpleChoice.new(node)
@@ -2,7 +2,7 @@ module Qti
2
2
  module V2
3
3
  module Models
4
4
  module Interactions
5
- class ExtendedTextInteraction < Qti::V2::Models::Base
5
+ class ExtendedTextInteraction < BaseInteraction
6
6
  @node_name = 'extendedTextInteraction'.freeze
7
7
  # This will know if a class matches
8
8
  def self.matches(node)
@@ -13,10 +13,6 @@ module Qti
13
13
  new(matches.first)
14
14
  end
15
15
 
16
- def initialize(node)
17
- @node = node
18
- end
19
-
20
16
  # not used yet
21
17
  def expected_lines
22
18
  @node.attributes['expectedLines']&.value&.to_i || 0
@@ -0,0 +1,52 @@
1
+ module Qti
2
+ module V2
3
+ module Models
4
+ module Interactions
5
+ class MatchInteraction < BaseInteraction
6
+ def self.matches(node)
7
+ matches = node.xpath('//xmlns:matchInteraction')
8
+ return false if matches.empty?
9
+
10
+ raise Qti::UnsupportedSchema if matches.size > 1
11
+ new(node)
12
+ end
13
+
14
+ def questions
15
+ node.xpath('.//xmlns:correctResponse//xmlns:value')
16
+ .map { |value| value.content.split.first }
17
+ .map { |id| { id: id, question_body: choices_by_identifier[id].content } }
18
+ end
19
+
20
+ def answers
21
+ answer_nodes.map { |node| Choices::SimpleAssociableChoice.new(node) }
22
+ end
23
+
24
+ def scoring_data_structs
25
+ question_response_pairs = node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
26
+ value.content.split
27
+ end
28
+ question_response_id_mapping = Hash[question_response_pairs]
29
+ data = question_response_id_mapping.reduce({}) do |acc, pair|
30
+ question_id, answer_id = pair
31
+ acc.update question_id => choices_by_identifier[answer_id].content
32
+ end
33
+ [ScoringData.new(data, 'directedPair')]
34
+ end
35
+
36
+ private
37
+
38
+ def choices_by_identifier
39
+ choices = node.xpath('.//xmlns:simpleAssociableChoice')
40
+ @choices_by_identifier ||= choices.reduce({}) do |acc, choice|
41
+ acc.update choice.attributes['identifier'].value => choice
42
+ end
43
+ end
44
+
45
+ def answer_nodes
46
+ node.xpath('.//xmlns:matchInteraction//xmlns:simpleMatchSet[2]//xmlns:simpleAssociableChoice')
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,7 @@
1
+ module Qti
2
+ module V2
3
+ module Models
4
+ ScoringData = Struct.new(:values, :type)
5
+ end
6
+ end
7
+ end
data/lib/qti.rb CHANGED
@@ -52,14 +52,20 @@ require 'qti/models/manifest'
52
52
  require 'qti/models/base'
53
53
 
54
54
  require 'qti/v1/models/base'
55
+ require 'qti/v1/models/interactions/base_interaction'
56
+ require 'qti/v1/models/interactions/choice_interaction'
55
57
  require 'qti/v1/models/assessment'
56
58
  require 'qti/v1/models/assessment_item'
57
59
  require 'qti/v1/models/choices/logical_identifier_choice'
60
+ require 'qti/v1/models/scoring_data'
58
61
 
59
62
  require 'qti/v2/models/base'
63
+ require 'qti/v2/models/interactions/base_interaction'
60
64
  require 'qti/v2/models/choices/simple_choice'
65
+ require 'qti/v2/models/choices/simple_associable_choice'
61
66
  require 'qti/v2/models/assessment_item'
62
67
  require 'qti/v2/models/assessment_test'
68
+ require 'qti/v2/models/scoring_data'
63
69
 
64
70
  require 'zip'
65
71
  require 'qti/exporter'
@@ -0,0 +1,74 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
3
+ <item title="" ident="4772">
4
+ <itemmetadata>
5
+ <qtimetadata>
6
+ <qtimetadatafield>
7
+ <fieldlabel>question_type</fieldlabel>
8
+ <fieldentry>matching_question</fieldentry>
9
+ </qtimetadatafield>
10
+ </qtimetadata>
11
+ </itemmetadata>
12
+ <presentation>
13
+ <material>
14
+ <mattext texttype="text/html">Match the statements with the correct type of microscope</mattext>
15
+ </material>
16
+ <response_lid ident="question_1" rcardinality="Single">
17
+ <material>
18
+ <mattext texttype="text/plain">Light Microscope</mattext>
19
+ </material>
20
+ <render_choice>
21
+ <response_label ident="8440">
22
+ <material>
23
+ <mattext texttype="text/plain">Magnify up to about 400 times. Sometimes requires colored staining of cells.</mattext>
24
+ </material>
25
+ </response_label>
26
+ <response_label ident="5653">
27
+ <material>
28
+ <mattext texttype="text/plain">Uses a beam of electrons. Can provide details of cells' internal structure.</mattext>
29
+ </material>
30
+ </response_label>
31
+ </render_choice>
32
+ </response_lid>
33
+ <response_lid ident="question_2" rcardinality="Single">
34
+ <material>
35
+ <mattext texttype="text/plain">Electron Microscopes</mattext>
36
+ </material>
37
+ <render_choice>
38
+ <response_label ident="8440">
39
+ <material>
40
+ <mattext texttype="text/plain">Magnify up to about 400 times. Sometimes requires colored staining of cells.</mattext>
41
+ </material>
42
+ </response_label>
43
+ <response_label ident="5653">
44
+ <material>
45
+ <mattext texttype="text/plain">Uses a beam of electrons. Can provide details of cells' internal structure.</mattext>
46
+ </material>
47
+ </response_label>
48
+ <response_label ident="7777">
49
+ <material>
50
+ <mattext texttype="text/plain">A distractor answer.</mattext>
51
+ </material>
52
+ </response_label>
53
+ </render_choice>
54
+ </response_lid>
55
+ </presentation>
56
+ <resprocessing>
57
+ <outcomes>
58
+ <decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
59
+ </outcomes>
60
+ <respcondition>
61
+ <conditionvar>
62
+ <varequal respident="question_1">8440</varequal>
63
+ </conditionvar>
64
+ <setvar varname="SCORE" action="Add">50.00</setvar>
65
+ </respcondition>
66
+ <respcondition>
67
+ <conditionvar>
68
+ <varequal respident="question_2">5653</varequal>
69
+ </conditionvar>
70
+ <setvar varname="SCORE" action="Add">50.00</setvar>
71
+ </respcondition>
72
+ </resprocessing>
73
+ </item>
74
+ </questestinterop>
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="ISO-8859-1"?>
2
2
 
3
- <questestinterop>
3
+ <questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
4
4
 
5
5
  <assessment title="Quiz" ident="A1001">
6
6
  <section title="Main" ident="S1002">
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="ISO-8859-1"?>
2
2
 
3
- <questestinterop>
3
+ <questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
4
4
 
5
5
  <assessment title="1.2 Import Quiz" ident="A1001">
6
6
  <section title="Main" ident="S1002">