Compile RELAX NG from both syntaxes and across documents: - A compact-syntax parser (lexer plus recursive descent) produces the same pattern algebra the XML syntax compiles to. It covers element and attribute declarations with name classes and namespace resolution, the , | & combinators and ? * + cardinality, text/empty/notAllowed, list and mixed, datatypes and value literals, grammars with start and named definitions (= |= &=), nested grammars, and include/external references. - The XML-syntax parser gains include (merging another grammar's definitions, with the include's own nested definitions overriding) and externalRef (resolving to an external schema's pattern), both through an injected loader. Both syntaxes reach the loader through a new schemaLoader parameter that returns nil by default, so compilation never touches the filesystem or network unless a loader is supplied. Closes #68
32 lines
1.5 KiB
Swift
32 lines
1.5 KiB
Swift
public extension PureXML.Schema {
|
|
/// A compiled RELAX NG schema (XML syntax). `validate(_:)` checks an instance
|
|
/// document by the derivative algorithm.
|
|
struct RelaxNG: Sendable {
|
|
private let start: Pattern
|
|
private let defines: [String: Pattern]
|
|
|
|
/// Compiles a RELAX NG schema document (XML syntax). `schemaLoader`
|
|
/// resolves the `href` of `include` and `externalRef` to schema source;
|
|
/// it returns nil (the default) when external schemas are not available.
|
|
public init(_ rng: String, schemaLoader: @escaping (String) -> String? = { _ in nil }) throws {
|
|
(start, defines) = try RelaxNGParser.parse(rng, loader: schemaLoader)
|
|
}
|
|
|
|
/// Compiles a RELAX NG schema in the compact syntax (RNC). `schemaLoader`
|
|
/// resolves `include` and `external` references to compact-syntax source.
|
|
public init(compact rnc: String, schemaLoader: @escaping (String) -> String? = { _ in nil }) throws {
|
|
(start, defines) = try RelaxNGCompactParser.parse(rnc, loader: schemaLoader)
|
|
}
|
|
|
|
/// Whether `xml` is valid against the schema.
|
|
public func validate(_ xml: String) throws -> Bool {
|
|
guard case let .document(children) = try PureXML.parse(xml),
|
|
let root = children.compactMap(\.element).first
|
|
else {
|
|
return false
|
|
}
|
|
return RelaxNGEngine(defines: defines).matches(start: start, root: .element(root))
|
|
}
|
|
}
|
|
}
|