PureXML/Sources/Parsing/DocumentType.swift
Mihaela Mihaljevic 89cb299201 feat(validation): DTD declaration-level validity constraints
VC Root Element Type (root matches the DOCTYPE name), VC Unique
Element Type Declaration, VC No Duplicate Types in mixed content, VC
One ID per Element Type, VC Notation Attributes and Notation Declared,
VC Attribute Default Legal plus ID Attribute Default, lexical Name
checks for the ID family, and CDATA as character data in element
content. Strict mode adds VC Attribute Value Type (every attribute
declared; namespace declarations exempt). Declaration findings are
computed once at schema build and reported at the document root. Sun
invalid coverage moves from 43/74 to 62/74; the twelve remaining are
all the standalone='yes' family.
2026-06-10 07:05:14 +02:00

55 lines
2.9 KiB
Swift

public extension PureXML.Parsing {
/// What the parser extracted from a `<!DOCTYPE>`: the internal general
/// entities, the `<!ELEMENT>` content-model strings, the `<!ATTLIST>` bodies,
/// the parameter entities, any external entity declarations, and the external
/// subset identifier. Empty when no DTD was processed.
struct DocumentType: Equatable, Sendable {
public var entities: [String: String]
public var elementModels: [String: String]
/// Raw `<!ATTLIST>` bodies keyed by element name (the text between the
/// element name and `>`, concatenated across multiple declarations).
public var attributeLists: [String: String]
/// Internal parameter entities (`<!ENTITY % name "value">`) keyed by name,
/// with their values already parameter-expanded. DTD-only; never visible
/// in document content.
public var parameterEntities: [String: String]
/// External general entity declarations keyed by name. Their replacement
/// text is loaded only through an injected ``EntityResolver``.
public var externalEntities: [String: ExternalID]
/// The external subset identifier from `<!DOCTYPE root SYSTEM/PUBLIC ...>`,
/// or nil when the DOCTYPE has no external subset.
public var externalSubset: ExternalID?
/// `<!NOTATION>` declarations keyed by name, with their external identifier.
public var notations: [String: ExternalID]
/// Unparsed general entities (`<!ENTITY name SYSTEM "..." NDATA n>`) keyed by
/// name. Their content is never parsed; the notation names how to handle it.
public var unparsedEntities: [String: UnparsedEntity]
/// The name in `<!DOCTYPE name ...>`: the root element's required type
/// (VC: Root Element Type).
public var name: String?
/// Element types declared by more than one `<!ELEMENT>` (VC: Unique
/// Element Type Declaration); the first declaration stays in effect.
public var duplicateElements: Set<String> = []
public init(
entities: [String: String] = [:],
elementModels: [String: String] = [:],
attributeLists: [String: String] = [:],
parameterEntities: [String: String] = [:],
externalEntities: [String: ExternalID] = [:],
externalSubset: ExternalID? = nil,
notations: [String: ExternalID] = [:],
unparsedEntities: [String: UnparsedEntity] = [:],
) {
self.entities = entities
self.elementModels = elementModels
self.attributeLists = attributeLists
self.parameterEntities = parameterEntities
self.externalEntities = externalEntities
self.externalSubset = externalSubset
self.notations = notations
self.unparsedEntities = unparsedEntities
}
}
}