PureXML/Sources/Schema/XSDAttributeParser.swift

56 lines
3.3 KiB
Swift

extension PureXML.Schema.XSDParser {
/// The attribute uses declared directly under `node` and through any
/// `attributeGroup` references it nests, flattened. The `visited` set guards
/// against attribute-group reference cycles.
static func attributeUses(under node: XSDTree, _ context: PureXML.Schema.XSDContext, visited: Set<String> = []) -> [PureXML.Schema.AttributeUse] {
var uses: [PureXML.Schema.AttributeUse] = []
for child in PureXML.Schema.XSDNode.elementChildren(node) {
switch PureXML.Schema.XSDNode.localName(child) {
case "attribute":
if let use = attributeUse(child, context) { uses.append(use) }
case "attributeGroup":
guard let ref = PureXML.Schema.XSDNode.attribute(child, "ref") else { break }
let name = PureXML.Schema.XSDNode.stripPrefix(ref)
guard !visited.contains(name), let group = context.attributeGroups[name] else { break }
uses += attributeUses(under: group, context, visited: visited.union([name]))
default:
break
}
}
return uses
}
static func attributeUse(_ node: XSDTree, _ context: PureXML.Schema.XSDContext) -> PureXML.Schema.AttributeUse? {
// An `<attribute ref="...">` references a global attribute declaration:
// take its name (always target-namespace qualified) and type from the
// global node, but `use`/`default`/`fixed` from this reference site.
if let ref = PureXML.Schema.XSDNode.attribute(node, "ref") {
let refName = PureXML.Schema.XSDNode.stripPrefix(ref)
guard let declaration = context.globalAttributes[refName],
var use = attributeUse(declaration, context) else { return nil }
let namespace = PureXML.Schema.XSDNode.referenceNamespace(ref, context.namespaceBindings)
use.name = PureXML.Model.QualifiedName(localName: refName, namespaceURI: namespace)
if PureXML.Schema.XSDNode.attribute(node, "use") == "required" { use.required = true }
if let constraint = valueConstraint(of: node) { use.valueConstraint = constraint }
return use
}
guard let name = PureXML.Schema.XSDNode.attribute(node, "name") else { return nil }
let required = PureXML.Schema.XSDNode.attribute(node, "use") == "required"
let type: PureXML.Schema.SimpleType = if let typeName = PureXML.Schema.XSDNode.attribute(node, "type") {
PureXML.Schema.XSDSimpleParser.simpleTypeReference(typeName, context)
} else if let inline = PureXML.Schema.XSDNode.firstChild(node, named: "simpleType") {
PureXML.Schema.XSDSimpleParser.simpleType(inline, context)
} else {
PureXML.Schema.SimpleType(base: .string, isAnySimpleType: true)
}
let qualified = PureXML.Schema.XSDNode.attribute(node, "form") == "qualified"
|| (PureXML.Schema.XSDNode.attribute(node, "form") == nil && context.attributeFormQualified)
return PureXML.Schema.AttributeUse(
name: PureXML.Model.QualifiedName(localName: name, namespaceURI: qualified ? context.targetNamespace : nil),
type: type,
required: required,
valueConstraint: valueConstraint(of: node),
)
}
}