PureXML/Sources/Schema/XSDSimpleContentParser.swift

67 lines
3.3 KiB
Swift

private typealias SimpleContentNode = PureXML.Schema.XSDNode
private typealias SimpleContentType = PureXML.Schema.SimpleType
private typealias SimpleContentContext = PureXML.Schema.XSDContext
private typealias SimpleContentBuiltinType = PureXML.Schema.BuiltinType
extension PureXML.Schema.XSDParser {
static func simpleContentType(
_ node: XSDTree,
_ context: PureXML.Schema.XSDContext,
visited: Set<String> = [],
) -> PureXML.Schema.SimpleType {
guard let inner = derivation(node) else { return SimpleContentType(base: .string) }
let rawBase = SimpleContentNode.attribute(inner, "base") ?? "string"
let baseName = SimpleContentNode.stripPrefix(rawBase)
let bindings = namespaceBindingsInScope(of: inner, defaultBindings: context.namespaceBindings)
let uri = SimpleContentNode.referenceNamespace(rawBase, bindings)
let baseType = simpleContentBaseType(baseName, uri: uri, context, visited: visited)
let effectiveType: SimpleContentType
let inlineType = SimpleContentNode.localName(inner) == "restriction"
? SimpleContentNode.firstChild(inner, named: "simpleType")
: nil
if let inline = inlineType {
effectiveType = scopedSimpleType(inline, context)
} else {
effectiveType = baseType
}
var facets = effectiveType.facets
let declaresEnumeration = SimpleContentNode.elementChildren(inner)
.contains { SimpleContentNode.localName($0) == "enumeration" }
if SimpleContentNode.localName(inner) == "restriction", declaresEnumeration {
facets.enumeration = nil
}
PureXML.Schema.XSDSimpleParser.applyFacets(inner, into: &facets)
return SimpleContentType(base: effectiveType.base, facets: facets, variety: effectiveType.variety, isBuiltinList: effectiveType.isBuiltinList)
}
static func scopedSimpleType(_ node: XSDTree, _ context: PureXML.Schema.XSDContext) -> PureXML.Schema.SimpleType {
var scoped = context
scoped.namespaceBindings = namespaceBindingsInScope(of: node, defaultBindings: context.namespaceBindings)
return PureXML.Schema.XSDSimpleParser.simpleType(node, scoped)
}
/// The simple type a `simpleContent` derivation derives from: an XSD built-in, a
/// named simple type, or, when the base is another complex type with
/// simpleContent, that type's own resolved simple type. A cycle in the base
/// chain falls back to `string`.
private static func simpleContentBaseType(
_ baseName: String,
uri: String?,
_ context: SimpleContentContext,
visited: Set<String>,
) -> SimpleContentType {
if uri == PureXML.Schema.XSDParser.xsdNamespace {
return SimpleContentType(base: SimpleContentBuiltinType(rawValue: baseName) ?? .string)
}
if let simple = context.simpleTypes[baseName] {
return simple
}
guard !visited.contains(baseName),
let complexNode = context.complexTypeNodes[baseName],
let baseSimpleContent = SimpleContentNode.firstChild(complexNode, named: "simpleContent")
else { return SimpleContentType(base: .string) }
return simpleContentType(baseSimpleContent, context, visited: visited.union([baseName]))
}
}