XML DTD Conditional Sections Using Parameter Entities

This article explains how XML Document Type Definitions (DTDs) use parameter entities to dynamically toggle conditional validation blocks. By combining parameter entities with INCLUDE and IGNORE directives, schema authors can selectively enable or disable element definitions, attribute lists, and other structural rules across different XML documents while maintaining a single, reusable DTD file.

The Mechanism of Conditional Sections

In an external XML DTD, conditional sections control which parts of the DTD the parser processes. These sections use the following syntax:

When hardcoded, these keywords are static. To make validation dynamic, the literal keyword (INCLUDE or IGNORE) is replaced by a parameter entity reference.

Controlling Sections with Parameter Entities

A parameter entity is a variable declared in a DTD using the % symbol. It can hold a string value representing either conditional keyword.

1. Declaring the Toggle Entity

Define a parameter entity with the value "INCLUDE" or "IGNORE":

<!ENTITY % useDraftFeatures "INCLUDE">
<!ENTITY % useProductionFeatures "IGNORE">

2. Referencing the Entity in Conditional Blocks

Substitute the keyword in the conditional section header with the parameter entity reference (%entityName;):

<![ %useDraftFeatures; [
    <!ELEMENT notes (#PCDATA)>
    <!ATTLIST document reviewStatus CDATA #IMPLIED>
]]>

<![ %useProductionFeatures; [
    <!ELEMENT publishedDate (#PCDATA)>
]]>

When the XML parser reads the DTD, it expands %useDraftFeatures; to INCLUDE, making the notes element valid. Simultaneously, %useProductionFeatures; expands to IGNORE, causing the parser to bypass the publishedDate declaration.

Dynamic Overriding via the Internal DTD Subset

The dynamic power of parameter entities comes from XML’s entity declaration precedence rules: declarations in the internal DTD subset override declarations in the external DTD subset.

An external DTD file (schema.dtd) can set default values:

<!-- schema.dtd -->
<!ENTITY % debugMode "IGNORE">

<![ %debugMode; [
    <!ELEMENT debugInfo (#PCDATA)>
]]>

Individual XML document instances can override this default inside their internal subset (<!DOCTYPE ... [...]>):

<?xml version="1.0"?>
<!DOCTYPE root SYSTEM "schema.dtd" [
    <!-- Override the external DTD default -->
    <!ENTITY % debugMode "INCLUDE">
]>
<root>
    <debugInfo>Diagnostic data here</debugInfo>
</root>

Because the internal subset declaration is parsed first, %debugMode; evaluates to INCLUDE for that specific XML instance, enabling the debugInfo element without modifying the shared schema.dtd file.