QTI Item Roundtrip
@citolab/prose-qti/item-roundtrip bundles the editor’s item import and export bridge. Use it when you want to move a single assessment item between QTI XML and ProseMirror without wiring the transform chain together yourself.
When to use this
Use this package when you need to:
- import a QTI 3.0 item XML string or URL into an editor document
- export a ProseMirror document back to a complete QTI assessment item
- keep the import transform chain, schema parsing, and export composer in one place
What it provides
The package exposes a small set of convenience helpers:
importItemFromStringimportItemFromUrlimportItemXmlDocexportItemXmlexportItemXmlDoc
It also exports the roundtrip transform and export option types so callers can type their integration code precisely, plus two prompt-handling helpers: ensureInteractionPrompts and stripEmptyPrompts (see Prompt handling below).
Typical usage
Import an item from a URL:
import { importItemFromUrl } from '@citolab/prose-qti/item-roundtrip';
const node = await importItemFromUrl('https://example.com/items/item-1.xml', schema);Export the current editor document:
import { exportItemXml } from '@citolab/prose-qti/item-roundtrip';
const xml = exportItemXml(editor.state.doc, schema, { identifier: 'item-1', title: 'Sample Item',});Prompt handling
Some editor schemas require a qti-prompt as the first child of block interactions such as order, match (including its tabular variant), associate, and gap-match — so authors always see a prompt slot to fill in, even though QTI 3.0 itself makes qti-prompt optional on these interactions. That mismatch needs a transform on both sides of the roundtrip:
-
On import,
ensureInteractionPrompts(schema)derives the set of interaction tags that require a leading prompt from the supplied schema, and injects an empty<qti-prompt><p/></qti-prompt>into any matching interaction whose source XML omits one. This is opt-in — append it toRoundtripImportOptions.transformsyourself, since only your schema knows whether a prompt is required:import { importItemFromString, defaultRoundtripTransforms, ensureInteractionPrompts } from '@citolab/prose-qti/item-roundtrip';const node = importItemFromString(xml, schema, {transforms: [...defaultRoundtripTransforms, ensureInteractionPrompts(schema)],}); -
On export,
stripEmptyPromptsremoves any<qti-prompt>whose text content is empty or whitespace-only before the item-body is wrapped in<qti-assessment-item>— sinceqti-promptis0..1in QTI 3.0, dropping an empty one is lossless. It’s part ofdefaultRoundtripExportTransformsand runs automatically; pass{ transforms: [] }to disable it, or your own list to customize.
Notes
- The caller still supplies the ProseMirror schema, because the editor schema is application-specific.
- Import uses the standard QTI 3.0 roundtrip transforms before parsing into ProseMirror.
- Export produces the same canonical item-body and full assessment-item XML used by the editor’s save flow.