PureXML/Sources/Schema/SchemaReferenceForeignPools.swift
Mihaela Mihaljevic 380160cc2b refactor(validation): decompose XSD instance validation into composable rules
The two monolithic XSD content/identity rules only satisfied the OpenAPIKit
validation idiom at the wrong granularity: no per-constraint removability,
no isolable failing/near-miss tests. Split them into 32 named rules, each
finding tagged at its origin and cached per XSDContext so the walk still
runs once per document (the #101 decision against duplicating XSD's
recursive type resolution still holds). Wired the streaming path's ID/IDREF
and identity checks through the same framework instead of calling the
validators imperatively, and added the unwrapAndLookup combinator the rule
already named as required.

Also includes the mandated repo-wide swiftformat/swiftlint pass.
2026-07-12 14:12:17 +02:00

69 lines
3.1 KiB
Swift

extension PureXML.Schema.XSDParser {
static func mergedNamespaceBindings(on node: XSDTree, inherited: [String: String]) -> [String: String] {
var bindings = inherited
for attribute in node.attributes {
if attribute.name.prefix == "xmlns" {
bindings[attribute.name.localName] = attribute.value
} else if attribute.name.prefix == nil, attribute.name.localName == "xmlns" {
bindings[""] = attribute.value
}
}
return bindings
}
/// Global component names in loaded containers outside the main target namespace.
static func foreignComponentPools(
_ containers: [XSDTree],
mainTargetNamespace: String?,
) -> [String?: [String: Set<String>]] {
let namespaceMap = resolveContainerNamespaces(containers, mainTargetNamespace: mainTargetNamespace)
var result: [String?: [String: Set<String>]] = [:]
for index in containers.indices {
let container = containers[index]
guard PureXML.Schema.XSDNode.localName(container) != "redefine" else { continue }
let namespaceURI = namespaceMap[index] ?? mainTargetNamespace
if namespacesMatch(namespaceURI, mainTargetNamespace) {
continue
}
var pools = result[namespaceURI, default: [:]]
insertNamedGlobals(from: container, into: &pools)
result[namespaceURI] = pools
}
return result
}
private static func insertNamedGlobals(from container: XSDTree, into pools: inout [String: Set<String>]) {
insertGlobalElements(from: container, into: &pools)
insertGlobalNames(child: "attribute", pool: "attribute", from: container, into: &pools)
insertGlobalNames(child: "group", pool: "group", from: container, into: &pools)
insertGlobalNames(child: "attributeGroup", pool: "attributeGroup", from: container, into: &pools)
insertGlobalNames(child: "simpleType", pool: "type", from: container, into: &pools)
insertGlobalNames(child: "complexType", pool: "type", from: container, into: &pools)
}
private static func insertGlobalElements(from container: XSDTree, into pools: inout [String: Set<String>]) {
for element in PureXML.Schema.XSDNode.children(container, named: "element") {
guard PureXML.Schema.XSDNode.attribute(element, "ref") == nil,
let name = PureXML.Schema.XSDNode.attribute(element, "name") else { continue }
pools["element", default: []].insert(name)
}
}
private static func insertGlobalNames(
child: String,
pool: String,
from container: XSDTree,
into pools: inout [String: Set<String>],
) {
for node in PureXML.Schema.XSDNode.children(container, named: child) {
if let name = PureXML.Schema.XSDNode.attribute(node, "name") {
pools[pool, default: []].insert(name)
}
}
}
private static func namespacesMatch(_ lhs: String?, _ rhs: String?) -> Bool {
lhs == rhs || ((lhs == nil || lhs == "") && (rhs == nil || rhs == ""))
}
}