# 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: ```bash 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. ```bash 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 ` ` 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](schema.md). 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](QTI_specification.md) for packaging details and the limits of structural verification. See the [command reference and troubleshooting guide](commands.md) for exit statuses and archive, CSV, overwrite, and filesystem diagnostics.