gizmobench

XML Schema Generator

Paste one XML document, or open a file, and get an XSD 1.0 schema drafted from it beside the text, with a table of every element and attribute and how often the sample shows it. Attributes and leaf text are kept (a leaf with attributes becomes simple content), repeated elements get maxOccurs unbounded, and every leaf and attribute stays xs:string until you pick another type, so an identifier such as 0012 keeps its zeros. Bounds, uses and types are editable, and the page says which part of the sample a setting would reject. Mixed content, namespaces, conflicting child order, recursion and DTDs are refused with the reason instead of being dropped, and the XML is read in your browser, never uploaded.

inventory.xsdworking

Starting the XML reader.

Elements
none yet
Repeated
none yet
Attributes
none yet
Leaf types
none yet

Paste XML, drop a file on the box, or open one: the schema redrafts as you type. Bounds, uses and types are set in the table below, and the XML is never stored or sent anywhere.

Three checks

Each row is what the code does with that input. Load puts it in the box.

  • Two adjacent item elements with code attributes and name and count textthe inventory example
    one repeated item declaration (minOccurs 1, maxOccurs unbounded), code kept as a required attribute, name and count as xs:string; xmllint, an independent XSD validator, accepts the sample
  • A value of 0012bin left at its default type
    bin is xs:string, so 0012 and 0340 keep their zeros; both also fit xs:integer, which is used only if you choose it
  • A DTD, an external entity, depth 65, mixed content or a namespacethis one: an external entity in a DTD
    refused before parsing, naming the DOCTYPE on line 1; nothing is fetched, and the input stays as you pasted it

How the draft is inferred

One declaration per path
The root element is the only global declaration. Every other element is declared inside its parent, with its children in the order the sample shows them, merged across parents when each shows part of that order.
minOccurs
1 when every parent in the sample holds the child, 0 when at least one parent lacks it.
maxOccurs
1 when no parent holds the child more than once, unbounded when any parent holds it twice or more. Either bound can be changed: the least from 0 to 5,000, the most from 1 to 5,000 or unbounded, and never below the least.
Attributes
An attribute on every instance of its element is use="required"; one missing from any instance is optional. Either can be changed.
Types
Every leaf and attribute starts as xs:string, so an identifier such as 0012 keeps its zeros. The table lists the other types every observed value fits (xs:integer, xs:decimal, xs:boolean, xs:date, xs:dateTime), with leading and trailing whitespace ignored as XSD ignores it for those types. A number fits only with up to 18 digits, which every XSD 1.0 validator must accept, and a date only with a four-digit year from 0001 to 9999. Another type is used only when you pick it.
Leaves
An element with no child elements anywhere in the sample is a leaf. A leaf with attributes becomes a complex type with simple content, so its text and its attributes are both kept.
Mixed content
Whitespace between elements is ignored. Text beside child elements in the same element is mixed content and is refused, and so is an element that holds text in one place and child elements in another. A CDATA section beside child elements counts as text, even an empty one, because xmllint (libxml2) rejects it there.
Refused with the reason
A namespace (any prefix, an xmlns declaration, xml:lang, an xsi: attribute), a DOCTYPE or other DTD declaration, an entity other than < > & " ' and numeric references, an element inside another of the same name at any depth, and children whose order conflicts, within one parent or between parents. No schema is offered until the sample is changed.
Limits
Up to 1 MiB of UTF-8, 10,000 nodes (elements, attributes, pieces of text, comments and processing instructions; whitespace between tags is not counted), depth 64 with the root at depth 1, and element paths such as /inventory/item/name up to 1,024 characters. All four are checked before the XML parser runs.
Your settings against the sample
If a bound, use or type you set would reject the sample, the page says which part of the sample fails. The schema can still be copied and downloaded.
Comments and examples
Comments and processing instructions are counted but not described: a schema has no place for them. Examples, when switched on, add the first non-empty value of each leaf and attribute, cut to 60 characters, as xs:documentation, escaped so it reads as text.
Accuracy. The schema describes the structure observed in your sample, not every document that could be valid later, so bounds and types stay editable. Leaves and attributes default to xs:string, so identifiers such as 0012 keep their zeros; mixed content, namespaces, conflicting child order and recursive structures are refused with a reason rather than dropped. Up to 1 MiB, 10,000 nodes and depth 64 are read in your browser, and the tool never fetches a DTD or external entity.

Common questions

How does it decide minOccurs and maxOccurs?
From how often each parent in the sample holds the child. minOccurs is 1 when every parent holds it and 0 when at least one does not; maxOccurs is 1 when no parent holds it more than once and unbounded when any holds it twice or more. In the example, two item elements sit in one inventory, so item is drafted as 1 to unbounded. Both bounds are editable (the least from 0 to 5,000, the most from 1 to 5,000 or unbounded), and if a bound you set would reject the sample, the page says where.
Why is every value typed as xs:string, even numbers?
A sample cannot tell a number from an identifier made of digits, such as a part code 0012 or a postal code, so every leaf and attribute starts as xs:string and keeps its value as written. The table lists the other types every observed value fits (xs:integer, xs:decimal, xs:boolean, xs:date or xs:dateTime), and a type changes only when you pick it. If a value in the sample does not fit your pick, the page quotes that value.
Does it keep attributes and elements that have both text and attributes?
Yes. An attribute seen on every instance of its element is declared use="required", and one missing from any instance is optional; either can be changed. An element with text and attributes but no child elements becomes a complex type with simple content, so the schema keeps its text type and its attributes together.
What does it refuse, and why not just skip it?
Mixed content (text, or a CDATA section, beside child elements), namespaces (prefixes, xmlns declarations, xml:lang, xsi: attributes), a DOCTYPE or other DTD declaration, entities other than XML's five and numeric references, an element nested inside another of the same name, and children whose order conflicts. Each is refused with the element and its path, or the line, instead of being dropped, because a schema that silently left something out would reject documents shaped like your sample. Your input stays in the box as it was.
Is the generated schema valid, and does it accept my sample?
It uses only XSD 1.0 constructs: one global element for the root, local elements in sequences, simple content extensions and attribute declarations. The tool's tests compile the schemas they draft with xmllint (libxml2) and validate each source sample against its schema; with the default settings, every sample passes. When a bound, use or type you set would reject the sample, the page lists each place it fails, and the schema can still be copied or saved as a .xsd file.
How large a file can it read?
Up to 1 MiB of UTF-8, 10,000 nodes (elements, attributes, pieces of text, comments and processing instructions), a depth of 64 and element paths up to 1,024 characters, all checked before the XML parser runs. A UTF-16 file, or a document that declares another encoding, is refused with a note to save it as UTF-8.
Is my XML uploaded or stored?
No. The XML is read in your browser by its built-in XML reader, after a check that refuses any DTD, so nothing it names is ever fetched. The text is never stored or sent; the only thing remembered on this device is whether you switched on example values.

The schema describes the structure observed in your sample, not every document that could be valid later, so bounds and types stay editable. Leaves and attributes default to xs:string, so identifiers such as 0012 keep their zeros; mixed content, namespaces, conflicting child order and recursive structures are refused with a reason rather than dropped. Up to 1 MiB, 10,000 nodes and depth 64 are read in your browser, and the tool never fetches a DTD or external entity.