XML to XSD Generator

Generate a starter XSD from sample XML, including attributes and simple value types. Every occurrence of an element is merged into one declaration, and foreign namespaces or an unstable child order are reported in the findings; review the schema before you use it.

Runs locally in your browser
Local processing ·

How to generate an XSD draft from sample XML

Paste a representative XML document, or press Load example for a small catalog sample, then press Generate XSD. The tool merges every occurrence of an element into one declaration and returns a starter schema you can copy or download as inferred-schema.xsd.

The document is parsed by the browser XML parser, so only well-formed XML produces output, and everything stays in the page: no upload, no validation service, no request to this site.

  1. Paste XML into the XML document editor, or press Load example to start from a known-good sample.
  2. Press Generate XSD. Malformed XML stops the run, and the status line plus the findings list name the line and column of the first parse error.
  3. Read the metrics above the output: inferred element declarations, input lines, size of the generated schema and the number of review notes.
  4. Read the findings. A note appears when child elements repeat in an unstable order, when the sample uses more than one namespace, or when it carries namespace-qualified attributes.
  5. Press Copy or Download to take inferred-schema.xsd, and Clear to empty the editor before the next document.

What the inference does — and what it leaves out

Types and cardinality

Value types follow the text of the sample. The literals true and false become xs:boolean; signed integers such as 42, 0, 1, -7 or 007 become xs:integer; 3.5, .5 and 5. become xs:decimal; 2026-08-29 and 2026-08-29T10:00:00Z become xs:date and xs:dateTime. Anything else — 0x1F, 1e3, TRUE — stays xs:string, because those spellings are not in the lexical space of the XSD types above.

Cardinality follows the occurrences. A child that repeats inside one element gets maxOccurs="unbounded"; a child that is missing from at least one occurrence of its parent gets minOccurs="0". Occurrences are merged rather than sampled, so a second tool element that adds an attribute or a child widens the declaration, and an element that appears empty in one place and filled in another stays optional.

Two shapes change the content model itself. Text that surrounds child elements produces complexType mixed="true", and children that repeat in a different order — item, note, item — become one xs:choice maxOccurs="unbounded" instead of a sequence, because a sequence would reject the sample it was generated from.

Namespaces and attributes

When the root element carries a namespace, that namespace becomes the targetNamespace of the generated schema with elementFormDefault="qualified", so the sample's own namespace survives the round trip. The xmlns declarations themselves never become attributes.

Elements from a different namespace cannot be declared in the same XSD document. They are emitted as one xs:any wildcard per foreign namespace with processContents="lax", so the sample still validates, and a finding records the trade-off. Namespace-qualified attributes such as xml:lang and xsi:type cannot be declared by name either; the type accepts them through xs:anyAttribute.

Plain attributes are declared unqualified and optional, with the same value-type rules as element text, and every occurrence of an attribute is unioned the way element children are.

What the draft cannot do

The page cannot check the generated schema against your XML: browsers ship no XSD validator. Compile and test the file with an XSD 1.0 processor — xmllint --schema, lxml or Saxon, for example — and keep the sample as a regression fixture. A schema that accepts one document can still be too narrow for the next one: an element that happened to be optional here, or a value that only looked like a date.

Only the sample is described. Constraints (xs:key, xs:unique, xs:length, patterns), comments and imports for further namespaces are not inferred and are not invented; add them by hand where they matter. Cardinality is a reading of this document, not a specification: nothing here states that a child must appear in production traffic.

Recent tools: