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.
57 lines
2.0 KiB
Swift
57 lines
2.0 KiB
Swift
public extension PureXML.Pattern {
|
|
/// Streams `xml` through the pull parser and returns the paths of every node
|
|
/// that matches `pattern`, in document order, without building a tree. Each
|
|
/// path is rendered root-first as `/a/b/c`, and an attribute match as
|
|
/// `/a/b/@id`. The match is decided from the open-element stack alone, so the
|
|
/// document is never held whole.
|
|
static func matches(
|
|
_ pattern: String,
|
|
in xml: String,
|
|
limits: PureXML.Parsing.Limits = .default,
|
|
) throws -> [String] {
|
|
let matcher = try Matcher(pattern)
|
|
return try matcher.matches(in: xml, limits: limits)
|
|
}
|
|
}
|
|
|
|
public extension PureXML.Pattern.Matcher {
|
|
/// Streams `xml` and returns the matching node paths in document order.
|
|
func matches(
|
|
in xml: String,
|
|
limits: PureXML.Parsing.Limits = .default,
|
|
) throws -> [String] {
|
|
var reader = PureXML.Parsing.EventReader(xml, limits: limits)
|
|
var stack: [PureXML.Model.QualifiedName] = []
|
|
var results: [String] = []
|
|
while let event = try reader.next() {
|
|
switch event {
|
|
case let .startElement(name, attributes):
|
|
stack.append(name)
|
|
collect(stack: stack, attributes: attributes, into: &results)
|
|
case .endElement:
|
|
if !stack.isEmpty {
|
|
stack.removeLast()
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
|
|
private func collect(
|
|
stack: [PureXML.Model.QualifiedName],
|
|
attributes: [PureXML.Model.Attribute],
|
|
into results: inout [String],
|
|
) {
|
|
let base = "/" + stack.map(\.description).joined(separator: "/")
|
|
if matchesAttributes {
|
|
for attribute in matchingAttributes(path: stack, attributes: attributes) {
|
|
results.append(base + "/@" + attribute.name.description)
|
|
}
|
|
} else if matchesElement(path: stack) {
|
|
results.append(base)
|
|
}
|
|
}
|
|
}
|