The namespace layer rejects malformed qualified names, declarations of the xmlns prefix, misbindings of the xml prefix and either reserved namespace name (including as the default namespace), and prefix undeclaration; attributes must be distinct by expanded name; PI targets and entity/notation names are NCNames; and DTD-typed xmlns values bind their normalized form. Clears all 18 namespace cases from the eduni baseline; xmltest valid/sa/012 joins the documented deviations per the suite's own NAMESPACE='no' flag. Closes #136
57 lines
2.7 KiB
Swift
57 lines
2.7 KiB
Swift
public extension PureXML.Parsing {
|
|
/// A located problem found while reading a document. Unlike a thrown
|
|
/// ``ParseError``, a diagnostic does not abort the read: the recovering reader
|
|
/// records it, repairs as best it can, and continues, so an invalid document
|
|
/// still yields a best-effort tree alongside the list of what went wrong.
|
|
struct Diagnostic: Equatable, Sendable, CustomStringConvertible {
|
|
/// A human-readable, already-located description of the problem.
|
|
public var message: String
|
|
/// The source position, when known.
|
|
public var mark: Mark?
|
|
|
|
public init(message: String, mark: Mark? = nil) {
|
|
self.message = message
|
|
self.mark = mark
|
|
}
|
|
|
|
public var description: String {
|
|
message
|
|
}
|
|
}
|
|
}
|
|
|
|
extension PureXML.Parsing.Diagnostic {
|
|
/// Wraps a thrown ``PureXML/Parsing/ParseError`` as a diagnostic, keeping its
|
|
/// located message and structured position.
|
|
init(_ error: PureXML.Parsing.ParseError) {
|
|
self.init(message: error.description, mark: error.mark)
|
|
}
|
|
}
|
|
|
|
public extension PureXML.Parsing.ParseError {
|
|
/// The source position the error occurred at, when the case carries one.
|
|
var mark: PureXML.Parsing.Mark? {
|
|
switch self {
|
|
case .emptyDocument, .malformedEncoding, .notImplemented:
|
|
nil
|
|
case let .unexpectedEndOfInput(mark), let .unterminatedTag(mark), let .unterminatedComment(mark),
|
|
let .unterminatedCDATA(mark), let .expectedName(mark), let .expectedEquals(mark),
|
|
let .unquotedAttributeValue(mark), let .amplificationLimitExceeded(mark),
|
|
let .junkAfterDocumentElement(mark), let .unsupportedDoctype(mark), let .malformedDeclaration(mark),
|
|
let .doubleHyphenInComment(mark), let .rawLessThanInAttribute(mark),
|
|
let .cdataCloseInContent(mark), let .missingSpaceBeforeAttribute(mark),
|
|
let .invalidCharacter(mark), let .reservedProcessingInstructionTarget(mark),
|
|
let .invalidEntityDeclaration(mark), let .invalidAttributeListDeclaration(mark),
|
|
let .invalidPublicIdentifier(mark):
|
|
mark
|
|
case let .unexpectedCharacter(_, mark), let .mismatchedEndTag(_, _, mark),
|
|
let .namespaceConstraint(_, mark),
|
|
let .duplicateAttribute(_, mark), let .invalidReference(_, mark),
|
|
let .undefinedEntity(_, mark), let .recursiveEntity(_, mark),
|
|
let .unexpectedEndTag(_, mark), let .undefinedNamespacePrefix(_, mark),
|
|
let .nestingTooDeep(_, mark), let .nameTooLong(_, mark), let .contentTooLong(_, mark), let .invalidContentModel(_, mark):
|
|
mark
|
|
}
|
|
}
|
|
}
|