dtd

package
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package dtd validates an XML document against the DTD in its internal subset.

It lives outside xdm because it needs the content-model automaton in xsd, and xdm is what xsd is built on — putting it there would invert the dependency. The split also keeps the parser's job clear: xdm reads a document and applies the two declarations whose absence is visible in the data model (attribute defaults and internal entities), while deciding whether the document *satisfies* its DTD is validation and belongs here.

Scope

A DTD is a smaller language than XSD, and almost all of it maps onto machinery that already exists:

  • <!ELEMENT> content models are a strict subset of what xsd's Glushkov automaton compiles — DTD has sequence, choice, and the ?, * and + quantifiers, and no numeric occurrence bounds at all.
  • <!ATTLIST> required/implied/fixed maps onto attribute use.
  • ID, IDREF and IDREFS are the same document-scoped uniqueness and reference checks XSD defines.

What DTD has that XSD does not is the *external* subset, which is a file reference. Fetching one is the attack AllowDOCTYPE exists to gate, so it is not read: a DOCTYPE naming an external subset validates against whatever its internal subset declares, and Validate says so rather than pretending the document was fully checked.

Index

Constants

View Source
const DefaultMaxErrors = 100

DefaultMaxErrors bounds how many failures are reported.

Variables

This section is empty.

Functions

func Validate

func Validate(doc *xdm.Node, d *DTD, opts Options) error

Validate checks a document against the DTD in its own internal subset.

The DTD is read from the document rather than supplied separately, which is what a DOCTYPE means. A document with no DOCTYPE is valid trivially: there are no constraints to violate.

The document must have been parsed with xdm.ParseOptions.AllowDOCTYPE set, since without it the parse fails before this is reachable.

What is checked: element content models, attribute presence (#REQUIRED and #FIXED), enumerated attribute values, and ID/IDREF. What is not: anything declared in an *external* subset, which is not fetched — Validate reports that as a limitation rather than passing the document silently.

Types

type AttrDefault

type AttrDefault int

AttrDefault is how an attribute's presence is constrained.

const (
	// AttrImplied is #IMPLIED: optional, no default.
	AttrImplied AttrDefault = iota
	// AttrRequired is #REQUIRED: must be present.
	AttrRequired
	// AttrFixed is #FIXED "v": if present the value must be v.
	AttrFixed
	// AttrDefaulted is a bare "v": supplied when absent.
	AttrDefaulted
)

type Attribute

type Attribute struct {
	Element string
	Name    string
	// Type is the declared type: CDATA, ID, IDREF, IDREFS, NMTOKEN,
	// NMTOKENS, ENTITY, ENTITIES, NOTATION, or an enumeration.
	Type string
	// Enum holds the permitted values of an enumeration or NOTATION type.
	Enum    []string
	Default AttrDefault
	Value   string
}

Attribute is one attribute definition within an <!ATTLIST>.

type ContentKind

type ContentKind int

ContentKind is what an element's content model permits.

const (
	// ContentEmpty is EMPTY: no child elements and no character data.
	ContentEmpty ContentKind = iota
	// ContentAny is ANY: anything, unchecked.
	ContentAny
	// ContentMixed is (#PCDATA | a | b)*: text interleaved with a set of
	// element names, in any order and any number.
	ContentMixed
	// ContentChildren is an element-only model such as (a, b*, (c|d)?).
	ContentChildren
)

type DTD

type DTD struct {
	// Elements maps an element name to its content model.
	Elements map[string]*Element
	// Attributes maps an element name to its declared attributes.
	Attributes map[string][]*Attribute
	// HasExternalSubset records that the DOCTYPE named a SYSTEM or PUBLIC
	// identifier. Nothing is fetched, so validation is against the internal
	// subset alone and callers are told rather than misled.
	HasExternalSubset bool
}

DTD is the subset of a document type declaration this package applies.

func Parse

func Parse(directive string) (*DTD, error)

Parse reads the declarations out of a DOCTYPE's internal subset.

The argument is the directive text as encoding/xml hands it over — the whole "DOCTYPE name [...]" including the brackets. Anything the grammar here does not recognise is skipped rather than guessed at, so an unusual declaration leaves the document less constrained rather than wrongly rejected.

type Element

type Element struct {
	Name string
	Kind ContentKind
	// Mixed is the set of names a mixed model admits. Order and repetition
	// are unconstrained there, so a set is the whole model.
	Mixed map[string]bool
	// Particle is the compiled model for ContentChildren, expressed in xsd's
	// component model so that the existing automaton can run it.
	Particle *xsd.Particle
}

Element is one <!ELEMENT> declaration.

type Error

type Error struct {
	// Path locates the element, as "/root/child".
	Path string
	// Message says what was wrong.
	Message string
}

Error is one validity failure.

func (*Error) Error

func (e *Error) Error() string

type Errors

type Errors struct{ Errors []*Error }

Errors is what Validate returns when a document is not valid.

func (*Errors) Error

func (e *Errors) Error() string

type Options

type Options struct {
	// MaxErrors stops after this many failures. Zero means
	// DefaultMaxErrors; a negative value means no limit.
	//
	// A document wrong in every element would otherwise produce an error per
	// element, which helps nobody and costs memory proportional to the input.
	MaxErrors int

	// AllowUndeclared skips elements the DTD says nothing about instead of
	// reporting them.
	//
	// Strictly, an undeclared element is a validity error: a DTD is a closed
	// description, unlike a schema where a wildcard may admit the unknown.
	// But a document whose DOCTYPE names an *external* subset and declares
	// only a few things internally is the common real-world shape — the
	// W3C's own RFC 3986 type library declares one element and one attribute
	// list, purely so that an external DTD's attributes work — and validating
	// that against its internal subset alone reports every other element as
	// undeclared, which is noise rather than a finding.
	//
	// Off by default, so the strict reading is what a caller gets unless they
	// ask otherwise. Turn it on when the DTD is known to be partial;
	// HasExternalSubset is how to detect that case.
	AllowUndeclared bool
}

Options configures Validate.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL