Getting Started
Installation
xml-model requires Zod v4 as a peer dependency.
bash
npm install xml-model zodNo special TypeScript compiler plugins or tsconfig.json changes are required.
First model
Define a class by extending the result of xmlModel(). Pass a Zod schema where fields are plain Zod types by default (child elements), xml.attr() for XML attributes, or xml.prop() when you need to customise a field's tagname, inline mode, or matching. Supply a { tagname } option for the root element name.
ts
/**
* A car engine. Extends `XMLBase` so unknown vendor elements inside `<engine>`
* (e.g. manufacturer extensions) survive a read-modify-write cycle.
* Demonstrates a basic nested class with one XML attribute (`type`) and one
* child element (`horsepower`).
*/
export class Engine extends XMLBase.extend(
{
/** Fuel type stored as an XML attribute: `<engine type="petrol">` */
type: xml.attr(z.string()),
/** Power output stored as a child element: `<horsepower>150</horsepower>` */
horsepower: z.number(),
},
xml.root({ tagname: "engine" }),
) {}ts
// XML → instance
const engine = Engine.fromXML(`<engine type="petrol"><horsepower>150</horsepower></engine>`);
engine.type; // "petrol"
engine.horsepower; // 150
engine instanceof Engine; // true
// instance → XML string
Engine.toXMLString(engine);
// <engine type="petrol"><horsepower>150</horsepower></engine>Class methods
Any methods you define on the class are available on parsed instances:
ts
/**
* Base vehicle class. Extends `XMLBase` so all vehicle subclasses inherit
* round-trip preservation — element order and unknown extensions are kept
* intact without any per-subclass ceremony.
* Demonstrates `xml.attr()` for identifier fields and custom instance methods.
*/
export class Vehicle extends XMLBase.extend(
{
/** Unique identifier stored as a root XML attribute: `<vehicle vin="...">` */
vin: xml.attr(z.string()),
/** Manufacturer name stored as a child element: `<make>Toyota</make>` */
make: z.string(),
/** Production year stored as a child element: `<year>2020</year>` */
year: z.number(),
},
xml.root({ tagname: "vehicle" }),
) {
/** Returns a human-readable label for this vehicle. */
label() {
return `${this.year} ${this.make}`;
}
}ts
const vehicle = Vehicle.fromXML(
`<vehicle vin="V001"><make>Toyota</make><year>2020</year></vehicle>`,
);
vehicle.label(); // "2020 Toyota"Next steps
- Models — class extension, nested models,
dataSchema,schema() - Properties —
xml.prop(),xml.attr(), arrays, optional fields