XML Tools
XML to XSD Generator — Infer a Schema from Sample XML
Paste a representative XML document, get a starting XSD with cardinality and types worked out — and an honest list of what one sample can never tell you.
In short
Generate an XSD from sample XML online: elements, attributes, minOccurs/maxOccurs from repetition, xs:integer/decimal/boolean/date inferred, Russian Doll or Venetian Blind.
By NaveenKumar T · Updated
- Elements, attributes and nesting from one sample
- minOccurs / maxOccurs from repetition
- xs:integer, decimal, boolean, date, dateTime inferred
Runs entirely in your browser — nothing you paste or open here is uploaded, logged, or stored.How we handle data →
Example
XML to XSD Generator: input and output
An order document with attributes on the root, a nested customer, two self-closing item elements and a decimal total — the same shape the [code generators](/generators) use, but the output here is a schema rather than typed classes.
<order id="ord_9F2KX" status="processing" paid="true">
<customer>
<name>Ada Lovelace</name>
<email>ada@example.com</email>
</customer>
<items>
<item sku="KB-75" qty="1" price="149.99"/>
<item sku="MS-12" qty="2" price="39.5"/>
</items>
<total>228.99</total>
</order><?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element name="customer" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="email" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="items" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="item" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="sku" type="xs:string" use="required"/>
<xs:attribute name="qty" type="xs:integer" use="required"/>
<xs:attribute name="price" type="xs:decimal" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="total" type="xs:decimal" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="status" type="xs:string" use="required"/>
<xs:attribute name="paid" type="xs:boolean" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>item got maxOccurs="unbounded" because the sample repeats it, qty became xs:integer, price and total became xs:decimal, paid became xs:boolean, and id, status and sku — none of them numeric-looking — stayed xs:string.
Learn more
How a sample XML becomes an XSD
The generator validates the document, then parses it with element order and repetition preserved — the same information a naive object-mode parser throws away — and builds one PROFILE per element name, merged across every place that name appears in the document. Each profile tracks which child elements and attributes showed up, how often, and what the text content and attribute values actually looked like.
From those profiles it emits xs:sequence blocks (child order follows first appearance), minOccurs/maxOccurs from presence and repetition, xs:attribute entries with use="required" or "optional", and a type for every leaf value — inferred from the text, never guessed from the element's name.
Value pattern → inferred XSD type
The exact rules Types: Infer applies, checked in this order until one matches; nothing matching falls back to xs:string.
| Value | Inferred type | Why |
|---|---|---|
| 42 | xs:integer | A plain integer, no leading zero |
| 007 | xs:string | A leading zero — likely a code, not a count |
| 3.50 | xs:decimal | Contains a decimal point |
| true | xs:boolean | Exact lowercase true/false |
| 2026-09-18 | xs:date | YYYY-MM-DD |
| 2026-09-18T09:30:00Z | xs:dateTime | ISO date-time |
| 1 in one instance, 1.5 in another | xs:decimal | Integer/decimal mix widens to decimal |
| KB-75 | xs:string | Doesn't match any numeric or date pattern |
Schema design styles
Where each style keeps its types, and when that trade-off pays off.
| Style | Where types live | Reuse | Readability |
|---|---|---|---|
| Russian Doll (default here) | Anonymous, nested inline in the element that uses them | None — every use redefines its type | One self-contained block, good for a single document |
| Venetian Blind (offered here) | Named global xs:complexType, referenced by type= | High — reference the same type from multiple elements | Flatter, easier to find a specific type by name |
| Salami Slice (not offered) | Every element AND type declared globally | Highest, but risks name collisions | Most verbose; rare in practice |
From inferred skeleton to a real contract
Treat the output as the typed, cardinality-aware starting point it is, not a finished contract: add xs:enumeration facets for fields with a fixed value set, xs:pattern for codes with a specific shape, minLength/maxLength/minInclusive/maxInclusive where the real format has limits, and switch xs:sequence to xs:choice anywhere your document actually offers alternatives rather than a fixed order. Once it's tightened, validate real documents against it — xmllint --schema, .NET's XmlReaderSettings.Schemas, and Java's SchemaFactory are the three most common ways, shown below. Explore the source document as a tree first in the XML Viewer, reformat it in the XML Formatter, or convert it to JSON with XML to JSON — and once an XSD exists, XML Validator covers well-formedness while a dedicated XSD validator (outside this tool) covers conformance to the schema itself.
| Platform | Command / API |
|---|---|
| Command line (libxml2) | xmllint --noout --schema schema.xsd file.xml |
| .NET | XmlReaderSettings.Schemas.Add(...) + an XmlReader validation callback |
| Java | SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(...) |
Help
Frequently asked questions
Everything you need to know about the XML to XSD Generator.
01How do I use the XML to XSD Generator?
Paste XML where every optional element appears at least once and every repeating element appears at least twice — a single occurrence can't prove either possibility — choose Russian Doll or Venetian Blind, and press Convert. Tighten the result by hand afterward: add enumerations, patterns and length facets a sample can't reveal.
02How does it decide minOccurs, maxOccurs and required attributes?
By repetition and presence across every instance of an element it finds anywhere in the document: a child element or attribute that shows up in EVERY instance of its parent is marked required (or minOccurs="1"); one that's missing from even a single instance becomes optional (minOccurs="0"). maxOccurs becomes "unbounded" the moment any single parent instance contains two or more occurrences of that child — a document with only one <item> gives no evidence it can repeat, so that field stays maxOccurs="1" until you paste a sample where it actually repeats. This is exactly why a single-instance sample understates a schema: the inference is honest about what it saw, not about what your format actually allows.
03Why is my numeric code typed xs:string?
Three deliberate safety nets, all designed to avoid inferring a type that would reject legitimate values: a value with a leading zero ("007", a product or postal code) stays a string, because xs:integer would silently accept "7" as equivalent and drop the leading zero's meaning; a field that mixes whole numbers and decimals across instances ("1" in one record, "1.5" in another) widens to xs:decimal rather than picking one and failing on the other; and a field that mixes numeric-looking values with anything else at all — even one non-numeric outlier in the sample — falls all the way back to xs:string, since a real production field that occasionally isn't numeric will keep not being numeric after you deploy the schema.
04What can an XSD generator not infer from a sample?
A sample proves what values CAN look like, never the full space of what they're ALLOWED to look like — that gap is the honest limit of any sample-driven generator, this one included. Specifically out of reach: enumerations (a status field with three sampled values might legally have thirty), pattern constraints (a product code's exact format), length and numeric-range facets (minLength, maxInclusive and friends), the choice between xs:sequence and xs:choice (a sample can't show "exactly one of these two children," only what happened to appear), xs:key/xs:unique identity constraints, and — the subtlest one — which ALWAYS-present elements in your sample are actually optional in the real format, since "present in every instance of a one-document sample" and "required by the format" are not the same claim. Treat the output as a typed skeleton to tighten by hand, not a finished contract.
05Russian Doll or Venetian Blind — which style should I pick?
Russian Doll (the default) nests every type anonymously inline inside the element that uses it, which reads well for a one-off document you're not going to reuse pieces of and keeps the whole schema in one visual block. Venetian Blind instead declares one named, global xs:complexType per element name — CustomerType, ItemType — and references those types by name, which pays off the moment a type needs reusing elsewhere in the schema, or when a large vocabulary benefits from types you can find by name instead of by scrolling through nested indentation. A third style some tools offer, Salami Slice (every ELEMENT, not just every type, declared globally and referenced), isn't offered here — it's the least common of the three in practice and adds a namespace-collision hazard this tool would rather avoid by default.
06Does it handle namespaces and prefixed elements?
A default xmlns="..." declaration on the root element becomes the schema's targetNamespace (with a matching xmlns and elementFormDefault="qualified" added), so an unprefixed document with a default namespace produces a schema that validates it correctly. Elements or attributes that use a NAMESPACE PREFIX (soap:Envelope, xsi:type) are handled more conservatively: the schema uses the local name only (Envelope, not soap:Envelope), and the status message tells you prefixed names were found — you add an xs:import for each additional namespace and wire up the prefix-to-namespace mapping by hand, since a sample alone doesn't carry enough information to safely reconstruct a multi-namespace import graph.
Keep working
Related tools
XML Validator
XML Tools
XML Formatter
XML Tools
XML to JSON
Parse any XML document into clean JSON — repeated elements become arrays, attributes preserved, text nodes kept.
JSON to JSON Schema
Paste a JSON or XML sample — the format is auto-detected — and get typed JSON Schema models with names, nesting and nullability inferred for you.
XML Viewer
XML Tools
SOAP Formatter
XML Tools