(Side note: In principle I would agree with using XSD instead of DTD (alternatively, use RelaxNG, which is a good, standardized alternative to XSD and much briefer plus much easier to understand and read). Don't worry too much about the extended code. It is quite easy to read and gives you a strong expressive power. Instead of being blocked by the technology, it will help you build what you need. IDEs like Visual Studio, Eclipse and others have graphical design tools for building your model which makes creating XSDs a breeze.)
But that doesn't answer your question. It is quite easy to reuse a definition in a DTD. Look at the HTML DTDs, it happens all the time. The key is to use parameter entities. Here's a simple example:
<!-- the "model" -->
<!ENTITY % commoncontent
"content | xxx">
<!ENTITY % commonattrs
"att1 CDATA #IMPLIED
att2 CDATA #IMPLIED">
<!-- elements -->
<!ELEMENT root ANY>
<!ELEMENT content ANY>
<!ELEMENT xxx EMPTY>
<!-- elements that share the same model -->
<!ELEMENT hello (%commoncontent;)+>
<!ELEMENT world (%commoncontent;)+>
<!-- adding the attributes to the elements with the same model -->
<!ATTLIST hello %commonattrs;>
<!ATTLIST world %commonattrs;>
which basically makes hello
and world
elements contain exactly the same set of attributes and content. I used a definition of non-mandatory and unordered elements as content, which makes the following XML document valid with the above DTD:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root SYSTEM "multipleSharedDefinitions.dtd">
<root>
<hello att1="bla">
<content />
</hello>
<world att1="bla" att2="blabla">
<content />
<xxx />
</world>
</root>