177 lines
8.2 KiB
Swift
177 lines
8.2 KiB
Swift
/// Type-compatibility findings for simpleType derivations and simpleContent
|
|
/// restrictions, split out so SchemaReferences.swift stays within the file
|
|
/// length budget.
|
|
extension PureXML.Schema.XSDParser {
|
|
static func simpleTypeBaseNotComplexFindings(_ schema: XSDTree, in context: PureXML.Schema.XSDContext) -> [PureXML.Schema.SchemaLocatedFinding] {
|
|
var findings: [PureXML.Schema.SchemaLocatedFinding] = []
|
|
let bindings = PureXML.Schema.XSDNode.namespaceBindings(of: schema)
|
|
let targetNamespace = context.targetNamespace
|
|
|
|
func isComplex(_ qname: String) -> Bool {
|
|
let trimmed = qname.trimmingXMLWhitespace()
|
|
let prefix = PureXML.Schema.XSDNode.prefix(trimmed)
|
|
let uri = prefix.flatMap { bindings[$0] } ?? bindings[""]
|
|
let local = PureXML.Schema.XSDNode.stripPrefix(trimmed)
|
|
if uri == xsdNamespace {
|
|
if targetNamespace == xsdNamespace {
|
|
return local == "anyType" || context.complexTypeNodes[local] != nil
|
|
} else {
|
|
return local == "anyType"
|
|
}
|
|
}
|
|
if uri == targetNamespace || uri == nil || uri == "" {
|
|
return context.complexTypeNodes[local] != nil
|
|
}
|
|
return false
|
|
}
|
|
|
|
func check(_ node: XSDTree) {
|
|
let local = PureXML.Schema.XSDNode.localName(node)
|
|
if local == "appinfo" || local == "documentation" {
|
|
return
|
|
}
|
|
|
|
if node.name?.namespaceURI == xsdNamespace {
|
|
switch local {
|
|
case "restriction":
|
|
Self.checkRestrictionUnderSimpleType(node, isComplex: isComplex, findings: &findings)
|
|
case "list":
|
|
Self.checkList(node, isComplex: isComplex, findings: &findings)
|
|
case "union":
|
|
Self.checkUnion(node, isComplex: isComplex, findings: &findings)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
for child in PureXML.Schema.XSDNode.elementChildren(node) {
|
|
check(child)
|
|
}
|
|
}
|
|
check(schema)
|
|
return findings
|
|
}
|
|
|
|
private static func checkRestrictionUnderSimpleType(_ node: XSDTree, isComplex: (String) -> Bool, findings: inout [PureXML.Schema.SchemaLocatedFinding]) {
|
|
guard let parent = node.parent, parent.name?.namespaceURI == xsdNamespace, PureXML.Schema.XSDNode.localName(parent) == "simpleType" else { return }
|
|
if let base = PureXML.Schema.XSDNode.attribute(node, "base"), isComplex(base) {
|
|
findings.append(PureXML.Schema.SchemaLocatedFinding(
|
|
reason: "base type '\(base)' of simpleType restriction must be a simple type, not a complex type",
|
|
node: node,
|
|
))
|
|
}
|
|
}
|
|
|
|
private static func checkList(_ node: XSDTree, isComplex: (String) -> Bool, findings: inout [PureXML.Schema.SchemaLocatedFinding]) {
|
|
if let itemType = PureXML.Schema.XSDNode.attribute(node, "itemType"), isComplex(itemType) {
|
|
findings.append(PureXML.Schema.SchemaLocatedFinding(
|
|
reason: "itemType '\(itemType)' of list must be a simple type, not a complex type",
|
|
node: node,
|
|
))
|
|
}
|
|
}
|
|
|
|
private static func checkUnion(_ node: XSDTree, isComplex: (String) -> Bool, findings: inout [PureXML.Schema.SchemaLocatedFinding]) {
|
|
if let members = PureXML.Schema.XSDNode.attribute(node, "memberTypes") {
|
|
for token in members.split(whereSeparator: \.isWhitespace) where isComplex(String(token)) {
|
|
findings.append(PureXML.Schema.SchemaLocatedFinding(
|
|
reason: "memberType '\(token)' of union must be a simple type, not a complex type",
|
|
node: node,
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
static func xsdNamespaceReferenceFindings(_ schema: XSDTree) -> [PureXML.Schema.SchemaLocatedFinding] {
|
|
let targetNamespace = PureXML.Schema.XSDNode.attribute(schema, "targetNamespace")
|
|
if targetNamespace == xsdNamespace {
|
|
return []
|
|
}
|
|
var findings: [PureXML.Schema.SchemaLocatedFinding] = []
|
|
let bindings = PureXML.Schema.XSDNode.namespaceBindings(of: schema)
|
|
|
|
func isUndeclaredBuiltin(_ qname: String) -> Bool {
|
|
let prefix = PureXML.Schema.XSDNode.prefix(qname)
|
|
let uri = prefix.flatMap { bindings[$0] } ?? bindings[""]
|
|
if uri == xsdNamespace {
|
|
let localName = PureXML.Schema.XSDNode.stripPrefix(qname)
|
|
return !referenceBuiltins.contains(localName)
|
|
}
|
|
return false
|
|
}
|
|
|
|
func check(_ node: XSDTree) {
|
|
let local = PureXML.Schema.XSDNode.localName(node)
|
|
if local == "appinfo" || local == "documentation" {
|
|
return
|
|
}
|
|
|
|
if node.name?.namespaceURI == xsdNamespace {
|
|
for attribute in ["type", "base", "itemType"] {
|
|
if let qname = PureXML.Schema.XSDNode.attribute(node, attribute), isUndeclaredBuiltin(qname) {
|
|
findings.append(PureXML.Schema.SchemaLocatedFinding(reason: "\(attribute) references undeclared type '\(qname)'", node: node))
|
|
}
|
|
}
|
|
if let members = PureXML.Schema.XSDNode.attribute(node, "memberTypes") {
|
|
for token in members.split(whereSeparator: \.isWhitespace) {
|
|
let qname = String(token)
|
|
if isUndeclaredBuiltin(qname) {
|
|
findings.append(PureXML.Schema.SchemaLocatedFinding(reason: "memberTypes references undeclared type '\(qname)'", node: node))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for child in PureXML.Schema.XSDNode.elementChildren(node) {
|
|
check(child)
|
|
}
|
|
}
|
|
check(schema)
|
|
return findings
|
|
}
|
|
|
|
static func simpleContentBaseFindings(_ schema: XSDTree, in context: PureXML.Schema.XSDContext) -> [PureXML.Schema.SchemaLocatedFinding] {
|
|
var findings: [PureXML.Schema.SchemaLocatedFinding] = []
|
|
let bindings = PureXML.Schema.XSDNode.namespaceBindings(of: schema)
|
|
let targetNamespace = context.targetNamespace
|
|
|
|
func check(_ node: XSDTree) {
|
|
let local = PureXML.Schema.XSDNode.localName(node)
|
|
if local == "appinfo" || local == "documentation" {
|
|
return
|
|
}
|
|
|
|
let isSimpleContentRestriction = node.name?.namespaceURI == xsdNamespace && local == "restriction"
|
|
&& node.parent?.name?.namespaceURI == xsdNamespace
|
|
&& node.parent.flatMap { PureXML.Schema.XSDNode.localName($0) } == "simpleContent"
|
|
if isSimpleContentRestriction {
|
|
if let base = PureXML.Schema.XSDNode.attribute(node, "base") {
|
|
let prefix = PureXML.Schema.XSDNode.prefix(base)
|
|
let uri = prefix.flatMap { bindings[$0] } ?? bindings[""]
|
|
let localPart = PureXML.Schema.XSDNode.stripPrefix(base)
|
|
if uri == targetNamespace || uri == nil || uri == "" {
|
|
if let baseNode = context.complexTypeNodes[localPart] {
|
|
let children = PureXML.Schema.XSDNode.elementChildren(baseNode)
|
|
let hasSimpleContent = children.contains { child in
|
|
child.name?.namespaceURI == xsdNamespace && PureXML.Schema.XSDNode.localName(child) == "simpleContent"
|
|
}
|
|
if !hasSimpleContent {
|
|
findings.append(PureXML.Schema.SchemaLocatedFinding(
|
|
reason: "base type '\(base)' of simpleContent restriction must be a simple type or complex type with simpleContent",
|
|
node: node,
|
|
))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for child in PureXML.Schema.XSDNode.elementChildren(node) {
|
|
check(child)
|
|
}
|
|
}
|
|
check(schema)
|
|
return findings
|
|
}
|
|
}
|