A Confusion of Styles
January 28, 2004
Q: How do I style a custom element's content?
I want two elements (QUESTION and ANSWER) to be declared in an external DTD. The QUESTION element's data is to be displayed in red, and the ANSWER element's data is to be displayed in green. For this, an external stylesheet needs to be used. How do I include the DTD in my HTML document?
Here's the relevant code:
queans.dtd:
<?xml-stylesheet type="text/css" href="clr.css"?>
<!ELEMENT QUESTION
(#PCDATA)>
<!ELEMENT ANSWER (#PCDATA)>
clr.css:
<STYLE>
QUESTION {font-family:arial;font-size:20pt;color:#ff0000}
ANSWER {font-family:arial;font-size:20pt;color:#00aa00}
</STYLE>
sample.htm:
<!DOCTYPE SYSTEM "queans.dtd">
<HTML>
<BODY>
<QUESTION>What is your favorite web site?</QUESTION>
<ANSWER>My
favorite web site is www.xml.com.</ANSWER>
</BODY>
</HTML>
A: As you've no doubt discovered, if you open this sample.htm in your favorite browser,
you'll see the content of the QUESTION
and ANSWER
elements all
right but displayed in the browser's default font (family, size, and color). You can
fix
this, but you'll have to straighten out some major misunderstandings first.
To recap, you've got a DTD which defines a couple of elements; a Cascading Style Sheet
which contains a STYLE
element; and an HTML document which (via the
DOCTYPE
declaration) points to the DTD and includes both elements defined
there, plus a couple of others (HTML
and BODY
). Among the numerous
confusions at work here:
- First, you don't need a DTD if all you want is to style an XML element's content when viewed in a browser. (I'll show you how to do this later.)
- Second, you really can't customize an HTML document by adding non-HTML elements (such
as
QUESTION
andANSWER
), using a DTD or by any other means. Browsers employ a variety of techniques to determine what sort of file or document they're asked to present to the user. (The simplest of these, also arguably the most common, is to look at the file's extension.) If a browser thinks it's reading an HTML document, it will display "known" HTML elements according to its default settings (for font, color, and so on) for that element -- unless overridden by a stylesheet. When it encounters an unknown element, however, all bets are off: it just displays the content in the same font, etc., used for plain old text (such as text contained in ap
element). Thus, your sample.htm file isn't a true HTML document; it's not even an XHTML document, but a document employing a hybrid, HTML-like XML vocabulary. - Third, if for some other reason you want to use a DTD, it needs to spell out everything which can be encountered in a document conforming to the DTD. If a document referencing the DTD includes HTML and BODY elements, then those elements must be declared in the DTD.
- Fourth, the association between a stylesheet and the content to be displayed is never
made in a DTD, or anywhere else for that matter, but in the document where the content
is
found. Note that this is true for both XML documents -- including XHTML ones -- and
garden-variety HTML ones.
- If you're working with a non-(X)HTML vocabulary, use an
xml-stylesheet
processing instruction just like the one you've mistakenly placed in your DTD. - If you're working with (X)HTML, place the reference to the external stylesheet in
a
LINK
element -- again, in the document where the content resides (sample.htm, in this case). (If you're using XHTML-with-an-X, all element and attribute names must be lowercase. ThusLINK
becomeslink
,BODY
becomesbody
, and so on.)
- If you're working with a non-(X)HTML vocabulary, use an
- Finally, in a CSS stylesheet, there's never anything but the style specifications:
you
especially don't include anything that looks like XML or HTML (like the
STYLE
element you've placed in clr.css).
If contemplating all of this hasn't completely exhausted you, here are some alternative solutions to your problem.
Simple customized display of an XML document
With this approach, as I said, you don't need a DTD at all. Just point the XML document to the right stylesheet. Corrected versions of your documents would then look as follows:
clr.css:
QUESTION {font-family:arial;font-size:20pt;color:#ff0000}
ANSWER
{font-family:arial;font-size:20pt;color:#00aa00}
sample.xml:
<?xml-stylesheet type="text/css" href="clr.css"?>
<HTML>
<BODY>
<QUESTION>What is your favorite web
site?</QUESTION>
<ANSWER>My favorite web site is
www.xml.com.</ANSWER>
</BODY>
</HTML>
Results when viewed in Mozilla:

(The Internet Explorer display is identical, except for the browser "chrome" of course.)
Simple display of an XHTML document
This is a little more complex, but still simple. The stylesheet remains the same as
above.
In the document itself, as I said, change all uppercase element and attribute names
to
lowercase. Furthermore, while it's not absolutely essential in the almost-anything-goes
world of browsers, you should formally associate your document with the XHTML vocabulary
in
two ways: (1) use a DOCTYPE declaration which points to the XHTML DTD of your choice,
and
(2) use an xmlns
attribute -- that is, a namespace declaration -- to
assert which of the document's elements are in the XHTML namespace. (Typically, all
elements in an "XHTML" document are in the XHTML namespace, but this needn't strictly
be the
case.) And finally, of course, you must add a link
element to connect your
document to clr.css
.
At this point, sample.htm
will now resemble the following (assuming you want
to use the XHTML "transitional" vocabulary), with the most significant changes in
boldface:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/TR/1999/REC-html-in-xml">
<link rel="stylesheet" type="text/css" href="clr.css" />
<body>
<QUESTION>What is your favorite web site?</QUESTION>
<ANSWER>My favorite web site is www.xml.com.</ANSWER>
</body>
</html>
In this case, browser behavior diverges: Mozilla's display of the content matches that of the previous solution. Internet Explorer, however, displays the question and answer in the browser's default font (family, size, and color). The "problem," I think, is that IE still doesn't recognize your QUESTION and ANSWER elements as XHTML. (Understandably, I might add. This seems to be a more correct behavior than Mozilla's.)
The only way to fix this is to replace your QUESTION and ANSWER elements with true
XHTML
elements, differentiating between them using class
attributes. Something like
this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/TR/1999/REC-html-in-xml">
<link rel="stylesheet"
type="text/css" href="clr.css" />
<body>
<span
class="QUESTION">What is your favorite web
site?</span>
<span class="ANSWER">My
favorite web site is www.xml.com.</span>
</body>
</html>
The implication of this change is that you must also change clr.css
's
selectors; here's a general solution:
.QUESTION {font-family:arial;font-size:20pt;color:#ff0000}
.ANSWER {font-family:arial;font-size:20pt;color:#00aa00}
(The dot preceding each selector associates that style with any element which has
a
class
attribute with the indicated value.)
Now both browsers again behave identically.
![]() |
|
Also in XML Q&A |
|
Getting fancier...
I don't mean "fancier" in terms of the display; I mean it in terms of how to
attain your objective. This solution builds on the previous one; it assumes that you
truly
do need those non-(X)HTML elements in your document, and you want to use the uppercase
element names. It simplifies some things, such as sample.htm
itself (which
returns to something very like its original form). The complexity comes from the addition
of
a second stylesheet -- this one in XSLT. Your document would now look something like
this:
<?xml-stylesheet type="text/xsl" href="clr.xsl"?>
<HTML>
<BODY>
<QUESTION>What is your favorite web
site?</QUESTION>
<ANSWER>My favorite web site is
www.xml.com.</ANSWER>
</BODY>
</HTML>
The XSLT stylesheet in question would specify the transformation of this simplified
sample.htm
into a result tree which more or less matches the version of
sample.htm
in the previous solution. Here's an XSLT stylesheet (just one of
many approaches, depending on how rigorous you need it to be) to accomplish this:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/1999/REC-html-in-xml">
<xsl:output method="xml"
version="1.0"
doctype-public="-//W3C//DTD
XHTML 1.0 Transitional//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" />
<xsl:template match="HTML">
<html>
<link rel="stylesheet"
type="text/css" href="clr.css" />
<xsl:apply-templates />
</html>
</xsl:template>
<xsl:template match="BODY">
<body><xsl:apply-templates
/></body>
</xsl:template>
<xsl:template match="QUESTION | ANSWER">
<span
class="{name()}"><xsl:apply-templates /></span>
</xsl:template>
</xsl:stylesheet>
(I'll leave readers to extract from this example those bits which most interest them.)
And how, you might wonder, do the browsers treat sample.htm
now? Sadly, they
ignore -- at least under Windows -- the result tree from this transformation; indeed
they
don't attend to the xml-stylesheet declaration at all. I suspect this is because of
that
operating system's stubborn reliance on filename extensions to determine how to treat
the
document: .htm
(or .html
) means the document is an (X)HTML
document and damn the consequences. Accordingly, sample.htm
displays exactly as
it did way back at the beginning of this answer, in default fonts and colors.
(Rather than shake your head in misery at this point, you might try changing the extension
to .xml
. Test it in both browsers. You'll find something else to shake your
head over.)
For what it's worth, if you run this most recent version of sample.htm
through
a standalone XSLT engine like Saxon, you'll see the result tree you need:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/TR/1999/REC-html-in-xml">
<link rel="stylesheet"
type="text/css" href="clr.css"/>
<body>
<span
class="QUESTION">What is your favorite web site?</span>
<span
class="ANSWER">My favorite web site is www.xml.com.</span>
</body>
</html>
If you save this result tree to a separate file, the browsers handle it just fine (and identically).
You may find this last alternative -- even though it's in some ways the most correct, requiring the least modification to your original source document -- a bit out of reach for now. Don't despair. Just keep asking questions and doing research.