Simple types and restrictions¶
A simple type describes the text content of an element or attribute — no
child elements, no attributes of its own. XSD ships with built-ins like
xsd:string, xsd:decimal, xsd:integer, and xsd:date. You rarely use them
raw: instead you derive a tighter type by adding constraints, called
facets, on top of a base type.
The workhorse is xsd:restriction:
| restriction-shape.xsd | |
|---|---|
baseis the type you are narrowing — a built-in or another named simple type.- Each child element is a facet. Stack as many as you need; a value must satisfy all of them.
A value that matches the base type but violates any facet is invalid.
Enumeration — closed value lists¶
xsd:enumeration is the code-list mechanism in XSD: list the permitted
values, and nothing else is allowed. UBL currency and document-type codes are
modelled exactly this way.
| currency-code.xsd | |
|---|---|
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode> — valid
<cbc:DocumentCurrencyCode>XYZ</cbc:DocumentCurrencyCode> — invalid (not in the list)
Note
The three codes above are an illustrative subset. Real code lists (ISO 4217 currencies, UBL document-type codes) follow the same pattern with far more members, and are often kept in a separate code-list schema.
Pattern — regular-expression constraint¶
xsd:pattern constrains the lexical form with a regular expression. The whole
value must match (the regex is implicitly anchored start-to-end). Use it for
structured identifiers.
| invoice-id.xsd | |
|---|---|
<cbc:ID>INV-001</cbc:ID> — valid
<cbc:ID>INV-1</cbc:ID> — invalid (needs exactly three digits)
<cbc:ID>X-001</cbc:ID> — invalid (wrong prefix)
Tip
Multiple xsd:pattern facets on one type are combined with OR — a value
matching any one of them passes.
Length — minLength, maxLength, length¶
These constrain the number of characters of a string (or items of a list).
| id-length.xsd | |
|---|---|
Use xsd:length for a fixed, exact size:
| country-code.xsd | |
|---|---|
- Exactly two characters — combine with
xsd:patternif you also need to restrict the alphabet.
FI — valid against CountryCodeType
FIN — invalid (length must be exactly 2)
Ranges — inclusive and exclusive bounds¶
For numeric and date/time types, the four bound facets set a permitted range.
Inclusive includes the boundary value; Exclusive excludes it.
| quantity-range.xsd | |
|---|---|
- Strictly greater than 0 — a zero quantity is rejected.
- Up to and including 1000.
The same facets work on dates, e.g. constraining an IssueDate to not precede
a fixed start date:
| issue-date.xsd | |
|---|---|
Decimal precision — totalDigits and fractionDigits¶
For monetary amounts, totalDigits caps the total number of significant digits
and fractionDigits caps the digits after the decimal point.
| amount.xsd | |
|---|---|
- At most 12 significant digits in all.
- At most 2 digits after the decimal point — the typical "minor unit" precision for money.
<cbc:LineExtensionAmount>10.90</cbc:LineExtensionAmount> — valid
<cbc:LineExtensionAmount>10.901</cbc:LineExtensionAmount> — invalid (3 fraction digits)
Info
In UBL the numeric part of an amount is a restricted xsd:decimal like
this, while the currency is carried separately in a currencyID attribute
typed by an enumeration such as CurrencyCodeType above.
Whitespace handling — whiteSpace¶
xsd:whiteSpace controls how whitespace in the lexical value is processed
before other facets are checked:
preserve— leave the value exactly as written.replace— turn each tab, newline, and carriage return into a space.collapse— applyreplace, then trim leading/trailing spaces and collapse internal runs to a single space.
| collapse.xsd | |
|---|---|
Note
String-derived built-ins like xsd:token already imply collapse; the
other built-ins (xsd:decimal, xsd:date, …) imply it too. You mostly set
this facet explicitly only when deriving directly from xsd:string.
Facet summary¶
| Facet | Constrains | Example |
|---|---|---|
xsd:enumeration |
Allowed values (closed list) | value="EUR" |
xsd:pattern |
Lexical form (regex) | value="INV-[0-9]{3}" |
xsd:length |
Exact string/list size | value="2" |
xsd:minLength / xsd:maxLength |
String/list size bounds | min 3, max 35 |
xsd:minInclusive / xsd:maxInclusive |
Range, boundary included | 0 ≤ x ≤ 1000 |
xsd:minExclusive / xsd:maxExclusive |
Range, boundary excluded | x > 0 |
xsd:totalDigits |
Total significant digits | value="12" |
xsd:fractionDigits |
Digits after the point | value="2" |
xsd:whiteSpace |
Whitespace processing | preserve / replace / collapse |
Lists and unions¶
Two more ways to build a simple type, without xsd:restriction.
xsd:list — a whitespace-separated sequence¶
A list type holds several values of one item type, separated by whitespace.
| code-list.xsd | |
|---|---|
- Each item must independently satisfy
CurrencyCodeType(the enumeration above).
EUR USD GBP — valid (three list items)
EUR XYZ — invalid (XYZ is not a member)
xsd:union — valid against any member type¶
A union accepts a value that matches any of its member types — handy when one field can carry either of two distinct shapes.
| reference-union.xsd | |
|---|---|
- A value is valid if it matches the
INV-NNNpattern or is one of the currency codes.
INV-001 — valid (matches InvoiceIdType)
EUR — valid (matches CurrencyCodeType)
abc — invalid (matches neither member)
Tip
xsd:list and xsd:union can themselves be wrapped in an xsd:restriction
— for example, to bound a list's length or enumerate the allowed union
values — letting you layer the three derivation styles.
Next¶
Continue with Modular schemas to see how these named simple types are split across files and reused — the way UBL keeps its code lists and component definitions in separate, importable schemas.