creatorvalet Search

XSD generator

Derive an XML schema from one example document — and read, line by line, which parts were measured and which were guessed.

  • SECURE
  • NO UPLOADS
  • NO SIGNUP
  • BROWSER BASED
  • FREE
  • FOREVER.

Support us with a link or a share

0 characters

The schema appears here as you paste or open an XML document.

What an XSD generator can and cannot know

Deriving a schema from an example is guessing with a good method. The document in front of the tool is one sample of a format, and a sample cannot tell you the rules — it can only tell you that these particular rules were not broken this particular time. Every generator on the first page of results does the guessing. What none of them do is say which parts were guessed.

That is the whole difference here. Anything this page could actually observe is written into the schema as a fact. Anything it had to assume is listed beside the schema with the path it applies to, what was seen there, and what the schema now claims as a result. You can read it in about thirty seconds and know exactly which three lines to check against a second document.

Why your number came out as a string

Because it had a leading zero. 007, 01606 and 00449 are all perfectly valid integers as far as XML is concerned, and they are all part numbers, zip codes or account references as far as everyone else is concerned. Type one of them xs:integer and every document validated against that schema afterwards loses its leading zeros — silently, in whatever consumes the data next, which is the worst place to find out.

So the rule is: digits with a leading zero are xs:string, and the tool says it did that. A plain 0 is a number, and so is 0.5 — the zero carries no information in either. The same conservatism applies to 1 and 0, which are valid xs:boolean as well as valid xs:integer. Guessing boolean there would turn every counter in every document into a flag, so it does not guess: only the literal words true and false get the boolean type.

Dates get the same treatment from the other direction. A string shaped like 2026-02-30 matches the pattern of an xs:date and is not one, because February has no thirtieth. It is typed as a string, and a real date such as 2024-02-29 is not.

minOccurs is measured where it can be, and admitted where it cannot

This is the inference that goes wrong most often and gets explained least. A single document can only demonstrate that something is optional where its parent repeats. If a catalog holds five books and three of them carry an ISBN, then minOccurs="0" on that ISBN is a measurement — the document showed you two books without one.

If the catalog holds one book, and that book carries an ISBN, absolutely nothing has been shown. The schema still has to say something, so it says minOccurs="1" maxOccurs="1", and the tool puts that path in the guessed list rather than letting it pass as a fact. The same logic covers attributes: a use="required" derived from an element that only ever appeared once is a guess, and it is labeled as one.

The practical consequence is that a better example beats a better generator. Two records where one omits an optional field will teach this page more than a thousand identical ones.

When the order of children is not fixed

An xs:sequence says the children appear in exactly this order. If two sibling elements in your document disagree about the order — one has first name then surname, the other the reverse — then a sequence would be a claim the document itself disproves, and the source file would fail its own schema.

There is no clean way out of this in XSD 1.0. xs:all allows any order but cannot carry maxOccurs, so it is useless for a repeating group. What this page emits instead is a repeating xs:choice, which accepts any order and any number of children. It is honest and it is weak, and the tool says so, because it is the one part of a derived schema most likely to need editing by hand.

Russian Doll, and why the other two designs are not offered

Schema authors talk about three styles. Russian Doll nests every definition inside one global element. Salami Slice declares every element globally and refers to them with ref. Venetian Blind names the complex types and keeps a single global element.

Only the first can be derived honestly from one document, and that is a consequence rather than a preference. The other two require an element name to have one definition across the whole schema — and real documents break that constantly. A <name> inside <author> is a string; a <name> inside <publisher> may have children of its own. Producing a Salami Slice or Venetian Blind schema from that example means merging two definitions the document never showed to be the same thing, which is an assumption wearing the clothes of a design choice. Russian Doll defines each element where it stands, so the two stay separate.

Namespaces, and the one thing this refuses to do

A document in a single namespace becomes a schema with that targetNamespace and elementFormDefault="qualified", which is what almost every real vocabulary uses. Attributes stay unqualified, because that is how almost every real vocabulary writes them.

A document using more than one namespace gets a refusal instead of a schema, and the refusal names the namespaces it found. A schema document has exactly one target namespace, so describing such a file correctly needs one schema per namespace joined with xs:import — and how you want those files split is a decision about your project, not something an example document can settle. An invented answer would be worse than no answer. Attributes in the xsi namespace, including xsi:schemaLocation, are ignored rather than turned into required attributes, because a validator allows them everywhere already.

Check the schema, do not trust it

Every schema this page writes is one it believes accepts the document it came from, and the belief is tested: the test suite runs each generated schema against its own source through libxml2 and requires a clean result, then mutates the source so that a field carries the wrong type and requires the same schema to reject it. That is a claim about the generator, though, not about your file.

For your file, take the schema next door. The XML validator runs libxml2 in the browser and will tell you what it thinks of the pair — and, far more useful, what it thinks of the next document that arrives from the same source. If the document needs tidying before you can read what it contains, the XML formatter lays it out first, and the XPath tester is the quickest way to find out whether the element you think is repeating actually is.

Nothing here leaves the tab

XML that needs a schema is rarely decorative. It is an integration payload, an invoice batch, a health record export, a bank statement, a government filing — the kind of document whose whole point is that it moves between two organizations under an agreement. Pasting one into an unknown page to get a schema out is a habit worth breaking.

The parser here runs in this tab, no DTD is fetched, no external entity is resolved, and an xsi:schemaLocation is read as text rather than opened. You can watch it: open your browser's network panel and then paste your document. Nothing appears, because there is nowhere for a request to go.

Have an idea for this tool?

Tell us what would make this tool more useful, or suggest another tool you would like us to build.

Questions

Can an XSD generator really work from one XML file?

It can produce a schema, and that schema will accept the document it came from. What it cannot do is know the rules of the format — one document is a sample. This tool separates the two: anything it could observe is stated as fact, and anything it had to assume appears in a list with the path, what was seen and what the schema now claims.

Why is my number typed as a string?

Because it had a leading zero. A value like 007 or 01606 is a valid integer to XML and a part number, zip code or account number to everyone else, and typing it xs:integer would silently drop the zeros from every document validated against the schema afterwards. Plain 0 and 0.5 are typed as numbers — the zero carries no information there.

Why does it say minOccurs cannot be known?

Because a single document can only show absence where a parent repeats. If five books appear and three carry an ISBN, minOccurs="0" is a measurement. If a book appears once and carries an ISBN, nothing at all has been shown, and minOccurs="1" is a guess — so it is listed as one instead of passing as a fact.

Which schema design style does it use?

Russian Doll — everything nested inside one global element — and that is a consequence rather than a preference. Salami Slice and Venetian Blind both require an element name to have a single definition across the whole schema, and real documents break that constantly: a name element inside author is a string, while a name inside publisher may have children of its own. Deriving those two from one example means merging definitions the document never showed to be the same.

Does my XML leave the browser?

No. The parser runs in this tab, no DTD or external entity is fetched, and an xsi:schemaLocation in your document is read as text and never opened. XML that needs a schema is usually an integration payload, an invoice or an export, which is exactly the kind of file that should not be pasted into a stranger.