10. XML Schema (XSD)

What you will learn

  • What an XML Schema is, and why it replaced DTDs
  • How to write a simple schema
  • Simple and complex types, sequences, and attributes
  • How to connect a document to its schema

What is an XML Schema?

XML Schema (often written XSD, for XML Schema Definition) is a language for describing the structure and content of XML documents. It does the job of a DTD, but better:

  • A schema is itself written in XML.
  • It has real data types: numbers, dates, true/false, and more.
  • It supports namespaces.
  • It can limit values, such as “a whole number from 1 to 100”.

A document and its schema

XML code: note.xml

<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Ali</to>
  <from>Sam</from>
  <message>See you at noon.</message>
</note>

XML code: note.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="note">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="to" type="xs:string"/>
        <xs:element name="from" type="xs:string"/>
        <xs:element name="message" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

What the schema says

  • There is one top-level element, note.
  • It is a complex type, meaning it has child elements.
  • Its children must appear in a sequence (in this order): to, from, message.
  • Each child holds a string of text.

The document above obeys these rules, so it is valid.

The schema uses the namespace you met earlier: http://www.w3.org/2001/XMLSchema, with the prefix xs (some authors use xsd). The prefix is only a shortcut, as you learned in the Namespaces lesson.

Simple and complex elements

Kind Meaning Example
Simple element Holds only text. No children, no attributes <age>25</age>
Complex element Has child elements, attributes, or both <person id="1">...</person>

A simple element is declared with a type attribute:

XML code

<xs:element name="age" type="xs:integer"/>

Controlling the arrangement

Inside a complex type, three indicators decide how children are arranged.

Indicator Meaning
xs:sequence Children must appear in this order
xs:choice Exactly one of the children
xs:all All children, in any order, each at most once

How many times?

Use minOccurs and maxOccurs. The default for both is 1.

XML code: library.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="library">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="book" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="title" type="xs:string"/>
              <xs:element name="subtitle" type="xs:string" minOccurs="0"/>
              <xs:element name="author" type="xs:string" maxOccurs="5"/>
              <xs:element name="price" type="xs:decimal"/>
            </xs:sequence>
            <xs:attribute name="id" type="xs:ID" use="required"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

What the schema says

  • A library holds one or more book elements (maxOccurs="unbounded" means no upper limit).
  • A book has a title, an optional subtitle (minOccurs="0"), one to five author elements, and a price that must be a decimal number.
  • A book must have an id attribute, and its value must be a unique ID.

Attributes

Attributes are declared inside the complex type, after the child elements. Use use="required" or use="optional" (the default), and default for a fallback.

XML code

<xs:attribute name="language" type="xs:language" default="en"/>

An element with text and an attribute

A price with a currency attribute needs an extension of a simple type.

XML code

<xs:element name="price">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="xs:decimal">
        <xs:attribute name="currency" type="xs:string" use="required"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>

What it accepts

<price currency="USD">12.50</price> is valid. <price>12.50</price> is not (the currency is missing), and <price currency="USD">cheap</price> is not (it is not a decimal).

Linking a document to its schema

A document can point to its schema with attributes from the XML Schema instance namespace:

XML code: note.xml

<?xml version="1.0" encoding="UTF-8"?>
<note xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="note.xsd">
  <to>Ali</to>
  <from>Sam</from>
  <message>See you at noon.</message>
</note>

This is a hint, and many tools let you give the schema separately instead, which is safer when the XML comes from someone else. If your schema uses a targetNamespace, link it with xsi:schemaLocation instead. That advanced case is beyond this lesson.

Validating against a schema

As with a DTD, browsers do not validate. Use an editor extension, xmllint, or code.

Terminal command

xmllint --noout --schema note.xsd note.xml

PHP code

<?php
libxml_use_internal_errors(true);

$doc = new DOMDocument();
$doc->load(__DIR__ . "/note.xml");

if ($doc->schemaValidate(__DIR__ . "/note.xsd")) {
    echo "The document is valid.";
} else {
    foreach (libxml_get_errors() as $error) {
        echo "Line " . $error->line . ": " . htmlspecialchars(trim($error->message), ENT_QUOTES, "UTF-8") . "<br>";
    }
    libxml_clear_errors();
}

Output for the valid note

The document is valid.

If you remove the from element and run it again, the loop prints messages saying an element is missing or unexpected, with a line number. The exact words depend on your library version.

Why use schemas?

  • They act as a contract between systems that exchange data.
  • They catch bad data before your program uses it.
  • Tools can use them to give auto-complete hints in editors, and to generate code.
  • They document the format clearly.

Remember, a schema makes data predictable, not safe. Still treat outside XML as untrusted, and avoid loading external resources from it.

Common mistakes

  • Forgetting the xs: prefix or its namespace declaration.
  • Declaring attributes before the child elements, or outside the complex type.
  • Using xs:sequence when order should not matter (use xs:all).
  • Expecting a browser to validate the file.
  • Mismatched element names between the schema and the document, since XML is case sensitive.

Exercise

Write a schema for <student> with child elements name (string) and score (integer), in that order, and a required attribute id (string).

Show solution
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="student">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="score" type="xs:integer"/>
      </xs:sequence>
      <xs:attribute name="id" type="xs:string" use="required"/>
    </xs:complexType>
  </xs:element>

</xs:schema>

Knowledge check

1. Why is XML Schema better than a DTD?

It is written in XML, has real data types, supports namespaces, and can restrict values.

2. What does maxOccurs="unbounded" mean?

The element may repeat any number of times.

3. Where are attributes declared in a schema?

Inside the complex type, after the child elements.

Summary

  • An XSD is an XML file that describes allowed structure, with simple and complex types.
  • Use xs:sequence, xs:choice, and xs:all for arrangement, and minOccurs and maxOccurs for counts.
  • Validate with a tool or code, because browsers do not.
Scroll to Top