Next come the individual declarations, and in well-commented DTDs each such declaration should also have a comment expanding on it in more detail. Let's begin with a simple element declaration, such as this one for an amount:
<!ELEMENT Amount (#PCDATA)>
All the declaration tells us is that the amount contains text and no child elements. It does not say whether this is an amount of money, an amount of time, an amount of oranges, or anything else. According to this declaration all of the following are valid:
<Amount>.45</Amount> <Amount>3.45</Amount> <Amount>-3.45</Amount> <Amount>(3.45)</Amount> <Amount>3.45 EUR</Amount> <Amount>+3.45 EUR</Amount> <Amount>23</Amount> <Amount /> <Amount>Oh Susanna, won't you sing a song for me?</Amount>
Naturally, the application likely has somewhat more rigid requirements than this. Although you can't enforce these requirements with a DTD, it is a very good idea to list them in a comment like this:
<!-- An amount element contains an amount of money, using two decimal places of precision for decimalized currencies; e.g., <Amount>3.45</Amount> Nondecimalized currencies such as yen are given as an integer; e.g. <Amount>3450</Amount> A leading minus sign is used to indicate a negative number. White space is not allowed. --> <!ELEMENT Amount (#PCDATA)>
The same is true for attribute values. For example, consider this ATTLIST declaration that declares a currency attribute. The type is NMTOKEN , but what else can be said about it?
<!ATTLIST Amount currency NMTOKEN "USD">
The following comment makes it clear that the value of the currency attribute is a three-letter ASCII currency code as defined by ISO 4217:2001 Codes for the Representation of Currencies and Funds . The default value can be read from the ATTLIST declaration, but it doesn't hurt to be more explicit.
<!-- Currencies are given as one of the three-letter codes defined by ISO 4217. Codes for countries where we have branches are: AUD Australian Dollar BRL Brazilian Real BSD Bahaman Dollar CAD Canadian Dollar CHF Swiss Franc DKK Danish Krone EUR European Currency Unit (Euro, formerly known as ECU) GBP British Pound JPY Japanese Yen KYD Cayman Dollar MXN Mexican Peso (new) MXP Mexican Peso (old) USD American Dollar The complete list can be found at http://www.gnucash.org/docs/C/xacc-isocurr.html. The default currency is U.S. dollars. -->
Sometimes when one type of value, such as money or currency, is going to be used for multiple elements in the DTD, it's useful to define it as a named parameter entity that can be referenced from different locations in the DTD. In this case, the comment moves on to discuss the parameter entity.
<!-- A money element uses two decimal places of precision for decimalized currencies and an integer for nondecimalized currencies. Noninteger, nondecimal currencies are not supported. A leading minus sign is used to indicate a negative number. White space is not allowed. --> <!ENTITY % money "(#PCDATA)"> <!ELEMENT Amount %money;>
General entities should also be commented. Sometimes if there are a lot of them, they're all related , and the names are descriptive enough, you can settle for a single comment for a group of entities. For example, this batch declares several currency symbols.
<!-- Currency symbols used in statements --> <!ENTITY YenSign "�xA5;"> <!ENTITY PoundSign "�xA3;"> <!ENTITY EuroSign "�x20AC;">
Comments can also be used and generally should be used for declarations of elements with complex types. For example, consider the following declaration of a transaction element.
<!-- A transaction element represents any action that moves money into or out of an account, including, but not limited to: * A withdrawal * A deposit * A transfer * A loan payment * A fee * Interest credit --> <!ELEMENT Transaction (Account?, Date, Amount)>
The comment gives a much clearer picture of just what a transaction element is for than the mere fact that each transaction has an optional account, followed by one date and one amount.
DTDs can be quite opaque and obscure, perhaps not as obfuscated as poorly written C++ but certainly worse than clean Python code. Even when the element and attribute names are properly verbose and semantic, it's always helpful to include comments clarifying the many things the declarations themselves can't say. Remember, in some cases the DTD isn't even used for direct validation. Its primary purpose is documentation. But even when a DTD is used for validation, its use as documentation is still very important. Proper commenting makes DTDs much more effective documentation for an application.