Importing QTI into YAML

QuestionBankToolkit imports a strict subset of QTI 1.2 single-answer multiple-choice packages. The input must be a ZIP package containing a root imsmanifest.xml in the supported IMS or Canvas Common Cartridge namespace whose QTI resource either contains the items directly or identifies one Canvas object bank through sourcebank_ref. Standalone XML, QTI 2.x, and other question types are not supported.

Archive safety limits

Before XML parsing, verification and import reject archives that exceed any of these limits:

Resource

Limit

ZIP members, including directory and unused entries

100

Uncompressed size of one member

16 MiB

Total declared uncompressed size

32 MiB

Uncompressed-to-compressed ratio of one nonempty member

100:1

Archive member names must also be unique. This prevents manifest or assessment lookup from depending on which duplicate entry a ZIP implementation chooses. The importer reapplies the policy when it reopens an archive and bounds the bytes read from each XML member.

These checks reduce memory and decompression risk; they do not make arbitrary QTI content safe or establish complete QTI conformance. QuestionBankToolkit reads the supported XML members directly and does not extract the package onto the filesystem.

Import a package with identity values for the new YAML bank:

coursebanks import-qti questions.zip \
  --course COURSE123 \
  --bank-id ImportedBank \
  --title "Imported question bank" \
  --out imported.yaml

The output path must not exist unless --force is supplied, and paths containing spaces are supported. Without --force, an existing file is preserved; with --force, it is replaced only after archive parsing and bank validation succeed. After import, review the YAML and validate it before using it to build another package.

coursebanks validate imported.yaml

Compatibility table

The classifications below describe the conversion into the YAML schema. Preserved values keep their supported QTI content, normalized values change representation deliberately, defaulted values are supplied when QTI has no supported source, and unsupported values are rejected or omitted as stated.

YAML field

Classification

Import behavior

schema_version

Defaulted

Always the integer 1.

course

Defaulted

Taken from the required --course argument, not from QTI.

bank_id

Defaulted

Taken from the required --bank-id argument and validated as a YAML identifier.

Bank title

Defaulted

Taken from the required --title argument, not from the QTI assessment title.

id

Preserved or normalized

Taken from item/@ident; a digit-leading identifier is prefixed with q_, while missing, duplicate, or otherwise schema-invalid IDs are rejected.

Question title

Normalized

Uses item/@title, removes an exact leading <id> prefix, and defaults to the item ID.

area

Defaulted

Uses CSV Area, QTI area, QTI topic, then Unclassified.

topic

Defaulted

Uses CSV Topic, QTI topic, then Unclassified.

difficulty

Normalized

Uses CSV Difficulty, QTI difficulty, then Moderate; Easy becomes Basic and High becomes Challenging.

assessments

Normalized

Uses CSV Assessments, CSV Suggested exam, QTI assessments, QTI suggested_exam, then unrestricted eligibility.

minutes

Defaulted

Uses CSV Suggested minutes, then 2.5; QTI does not supply this authoring estimate.

points

Preserved or defaulted

Uses QTI points_possible, then 2; integral values are written as integers.

format

Normalized

QTI text/plain becomes plain, and text/html becomes html.

stem

Preserved

Uses the supported presentation mattext content.

choices

Normalized

Preserves source order and text but replaces source identifiers with A through Z; 2–26 choices are supported.

shuffle_choices

Normalized

QTI render_choice/@shuffle="Yes" becomes true; No or an omitted attribute becomes false.

answer

Normalized

Translates the source choice identifier from one full-credit score condition to its generated A–Z label.

explanation

Preserved or defaulted

Uses general feedback mattext; when the package contains no feedback container, records No explanation was provided in the imported QTI package. explicitly, while malformed feedback is rejected.

Additional YAML metadata

Unsupported

QTI fields without a mapping above are not copied into YAML.

Imported choices deliberately receive new labels. For example, source identifiers red-option, blue.option, and answer_42 become A, B, and C in source order, and a correct answer of blue.option becomes B.

Metadata CSV overrides

Use --metadata-csv PATH to provide authoring information that QTI does not contain reliably. The CSV must contain a case-sensitive ID column matching QTI item identifiers. Supported columns are Area, Topic, Difficulty, Suggested minutes, Assessments, and the legacy Suggested exam. The Assessments cell contains a JSON array such as ["Quiz 1", "Homework"]. Use [] to request unrestricted eligibility explicitly. Empty cells do not override QTI metadata or importer defaults.

Eligibility precedence is:

  1. Nonempty CSV Assessments.

  2. Nonempty CSV Suggested exam.

  3. QTI assessments.

  4. QTI suggested_exam.

  5. Unrestricted eligibility.

CSV Area, Topic, Difficulty, and Suggested minutes override their corresponding QTI-derived or default values independently. The metadata CSV cannot override question text, choices, answers, explanations, points, formats, or shuffling.

Supported item structure

Each item must contain one single-cardinality response_lid, one render_choice, 2–26 choices, and consistent text/plain or text/html content. The importer requires one uniquely identifiable choice whose score condition sets SCORE to 100; it accepts either that single rule or an additional fallback score rule. Canvas Common Cartridge exports may place the actual items in a manifest resource referenced by a wrapper assessment’s sourcebank_ref, and that one level of indirection is resolved explicitly. Unsupported response types, partial or ambiguous scoring, missing identifiers, inconsistent text formats, ambiguous source-bank references, media dependencies, and unrepresentable content are rejected rather than silently discarded.

The importer validates the completed bank against the YAML schema. Passing import and validation proves compatibility with this toolkit’s supported subset, not rendering or acceptance by Canvas. See the QTI export and import contract for packaging details and the limits of structural verification. See the command reference and troubleshooting guide for exit statuses and archive, CSV, overwrite, and filesystem diagnostics.