This introductory tutorial doesn't go into great detail about how DTDs work, but there's one more basic topic to cover here: defining attributes. You can define attributes for the elements that will appear in your XML document. Using a DTD, you can also:
- Define which attributes are required
- Define default values for attributes
- List all of the valid values for a given attribute
Suppose that you want to change the DTD to make state an attribute of the <city> element. Here's how to do that:
<!ELEMENT city (#PCDATA)>
<!ATTLIST city state CDATA #REQUIRED>
This defines the <city> element as before, but the revised example also uses an ATTLIST declaration to list the attributes of the element. The name city inside the attribute list tells the parser that these attributes are defined for the <city> element. The name state is the name of the attribute, and the keywords CDATA and #REQUIRED tell the parser that the state attribute contains text and is required (if it's optional, CDATA #IMPLIED will do the trick).
To define multiple attributes for an element, write the ATTLIST like this:
<!ELEMENT city (#PCDATA)>
<!ATTLIST city state CDATA #REQUIRED
postal-code CDATA #REQUIRED>
This example defines both state and postal-code as attributes of the <city> element.
Finally, DTDs allow you to define default values for attributes and enumerate all of the valid values for an attribute:
<!ELEMENT city (#PCDATA)>
<!ATTLIST city state CDATA (AZ|CA|NV|OR|UT|WA) "CA">
The example here indicates that it only supports addresses from the states of Arizona (AZ), California (CA), Nevada (NV), Oregon (OR), Utah (UT), and Washington (WA), and that the default state is California. Thus, you can do a very limited form of data validation. While this is a useful function, it's a small subset of what you can do with XML schemas (see XML schemas).