Element and Attribute Decls

Element and Attribute Declarations

<!ELEMENT name content> declares an element whose content is EMPTY, ANY, (#PCDATA), mixed (#PCDATA | b)*, or a model of children joined by , (in order) or | (choice) with ?, * and + for occurrence. <!ATTLIST element name type default> declares attributes of type CDATA, an enumeration, ID, IDREF(S), NMTOKEN(S) (name characters, which unlike a name may start with a digit), or the legacy ENTITY and NOTATION; the default is a value, #REQUIRED, #IMPLIED or #FIXED "value". The BookNest catalog as a DTD:

booknest.dtd: the catalog feed's structureXML
<!ELEMENT catalog (header, book+)>      <!ATTLIST catalog xml:lang NMTOKEN #IMPLIED>
<!ELEMENT header (sender, sent, records)>
<!ELEMENT book (identifier, title, contributor+, subject, pages, published, summary,
                rating, supply)>       <!ATTLIST book id ID #REQUIRED>
<!ELEMENT contributor (name, sort-name)>
<!ATTLIST contributor role (author | editor) #REQUIRED  seq CDATA "1">
<!ATTLIST identifier type (sku | isbn13) "sku">   <!ATTLIST subject scheme CDATA #REQUIRED>
<!ELEMENT supply (availability, price)> <!ATTLIST price currency CDATA #FIXED "USD">
<!ELEMENT sender (#PCDATA)>     <!ELEMENT sent (#PCDATA)>     <!ELEMENT records (#PCDATA)>
<!ELEMENT identifier (#PCDATA)> <!ELEMENT title (#PCDATA)>    <!ELEMENT name (#PCDATA)>
<!ELEMENT sort-name (#PCDATA)>  <!ELEMENT subject (#PCDATA)>  <!ELEMENT pages (#PCDATA)>
<!ELEMENT published (#PCDATA)>  <!ELEMENT summary (#PCDATA)>  <!ELEMENT rating (#PCDATA)>
<!ELEMENT availability (#PCDATA)>                             <!ELEMENT price (#PCDATA)>

--dtdvalid needs no DOCTYPE in the file but printed only a one-line verdict for the broken copy below (a duplicate ID, an unknown role, a missing rating); a linked DTD with --valid gives details:

Validating the catalog and a broken copy against the DTD
xmllint --noout --dtdvalid booknest.dtd booknest-catalog.xml && echo "catalog is valid"
sed -e '1a <!DOCTYPE catalog SYSTEM "booknest.dtd">' -e 's/id="b3"/id="b2"/' \
    -e '0,/role="author"/s//role="writer"/' -e '0,/<rating>4.6<\/rating>/s///' \
    booknest-catalog.xml > broken.xml
xmllint --noout --valid broken.xml 2>&1 | grep error
Output
catalog is valid
broken.xml:13: element contributor: validity error : Value "writer" for attribute role of
  contributor is not among the enumerated set
broken.xml:27: element book: validity error : Element book content does not follow the DTD,
  expecting (identifier , title , contributor+ , subject , pages , published , summary ,
    rating , supply), got (identifier title contributor subject pages published summary supply
      )
broken.xml:46: element book: validity error : ID b2 already defined

Every leaf is untyped #PCDATA (price could hold "-3"), and names match literally, prefixes included.