lutaml-xsd 1.2.101 → 1.2.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0406cd7f1ca030db5b4c6db63f060fdaae3981f61d2913f3552c510129f80b8c
|
|
4
|
+
data.tar.gz: 067f44365c98c7a9b3fd221c74d35965d5e628b3cb58f788e7210bd8a8cc6964
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d7b9a1f01944bfe42b257e750226f2e9b200fbe3a30fe14ac834f3b1b7fdd675a12afb77764eaf821e09662674788ecf764064516477e26df394da4ba8b66ac2
|
|
7
|
+
data.tar.gz: 8dc0ac9729456a8903c6a2f70c4db8d1d2c7704076654ac173c4450aa089c76d3369a48f61d1638c210e26cd5b94584cebeff2af4700bdf3964b587136082183
|
data/TODO.conformance.md
CHANGED
|
@@ -519,7 +519,50 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
|
|
|
519
519
|
0.6.3 + lutaml-model 0.8.166 train carried fixes (the FULL #45
|
|
520
520
|
stE legs, the #522 attgC four + attgD mostly + attJ018 +
|
|
521
521
|
schF1/P2, stE065/066/096) AND a WHOLESALE 407 regex regression:
|
|
522
|
+
- PARENT-CONTEXT ROUND B (2026-11-08): +1 Additional (isDefault079;
|
|
523
|
+
suite 4629->4630 = 98.59%, zero regressions, rspec green).
|
|
524
|
+
POSITIONAL BINDING for duplicate same-named locals: a model with
|
|
525
|
+
two regvalueop locals carrying DIFFERENT fixed values never bound
|
|
526
|
+
the second child to the second particle — the name-only dispatch
|
|
527
|
+
always hit the first. The engine computes each child's same-name
|
|
528
|
+
sibling index (on the RAW moxml nodes — wrapper objects are not
|
|
529
|
+
identity-stable across accessor calls, the IdUniquenessRule
|
|
530
|
+
lesson) and dispatches the positionally-bound declaration when
|
|
531
|
+
(a) the parent's model holds MORE THAN ONE same-named particle,
|
|
532
|
+
(b) every particle is INDEXED (attempt-3's starvation guard: raw
|
|
533
|
+
parent-model particles carry none of the form/ns metadata the
|
|
534
|
+
rules assume — resolver positional_children returns [] otherwise),
|
|
535
|
+
and (c) the candidate's expected namespace AGREES with the child's
|
|
536
|
+
(particlesQ016's global/local namesake guard). The ordered walk
|
|
537
|
+
keeps a PER-CALL visited set — the resolver's
|
|
538
|
+
each_particle_element memoizes on the instance and would poison
|
|
539
|
+
repeats. LESSON: scripted line-surgery on lib files dropped a
|
|
540
|
+
class end and leaked methods to top level (runtime-only
|
|
541
|
+
uninitialized-constant failures, caught by sentinel probes) —
|
|
542
|
+
structural edits go through the Edit tool only. Remaining parked
|
|
543
|
+
(matcher-assignment + root-assessment shapes): QFE1700c1,
|
|
544
|
+
addB065, addB188, schA1/D10 + the lax-wildcard six.
|
|
545
|
+
|
|
522
546
|
~177 cases — the ENTIRE Unicode-block escape family (~80
|
|
547
|
+
- PARENT-CONTEXT ROUND A (2026-11-08): +1 Errata10 (errC007; suite
|
|
548
|
+
4628->4629 = 98.57%, zero regressions, rspec green). The
|
|
549
|
+
parent-context redesign opens with an ENGINE-LEVEL win: anyType
|
|
550
|
+
content is LAX — a child validates only against a declaration in
|
|
551
|
+
its OWN namespace, so a strictly-unresolvable child of an anyType
|
|
552
|
+
element (including one the namespace fallback would have served
|
|
553
|
+
from a targeted schema) is lax-undeclared and its subtree escapes
|
|
554
|
+
assessment (the suppression rides the existing skip-wildcard walk,
|
|
555
|
+
hereditary like QFE1700a1). The resolver gains resolve_strict
|
|
556
|
+
(exact-namespace only) and the shared anyType reference check.
|
|
557
|
+
errC007's contract is now enforced WITHOUT the namespace-fallback
|
|
558
|
+
narrowing that regressed five substitution/import shapes — those
|
|
559
|
+
lookups never touch this path. Round B (next): positional binding
|
|
560
|
+
for duplicate same-named particles (isDefault079) — ordered
|
|
561
|
+
per-call walk (the resolver's visited_particle? memoizes on the
|
|
562
|
+
instance and would poison repeats), gated on >1 same-named
|
|
563
|
+
particles AND all indexed (@namespaces.key? — the attempt-3
|
|
564
|
+
starvation guard).
|
|
565
|
+
|
|
523
566
|
\p{Is...} per-block tests) plus the reL/reP/reQ/reR/reS/reT
|
|
524
567
|
- ANYSIMPLETYPE-WHITESPACE ROUND (2026-11-07): +1 Additional
|
|
525
568
|
(test93160; suite 4627->4628 = 98.55%, pending measure confirm).
|
|
@@ -58,12 +58,32 @@ module Lutaml
|
|
|
58
58
|
# empty xs:int child escapes assessment too).
|
|
59
59
|
next true if subtree_suppressed
|
|
60
60
|
|
|
61
|
-
skip_here = skip_wildcard_subtree?(parent, xml_element, resolver)
|
|
61
|
+
skip_here = skip_wildcard_subtree?(parent, xml_element, resolver) ||
|
|
62
|
+
lax_any_type_child?(parent, xml_element, resolver)
|
|
62
63
|
next true if skip_here
|
|
63
64
|
|
|
64
65
|
schema_def = resolver.resolve(
|
|
65
66
|
xml_element.name, xml_element.namespace_uri
|
|
66
67
|
)
|
|
68
|
+
if parent
|
|
69
|
+
parent_declaration =
|
|
70
|
+
resolver.resolve(parent.name, parent.namespace_uri)
|
|
71
|
+
candidates = resolver.positional_children(parent_declaration,
|
|
72
|
+
xml_element.name)
|
|
73
|
+
positional = candidates[same_name_sibling_index(xml_element,
|
|
74
|
+
parent)]
|
|
75
|
+
# The binding must agree with the child's OWN namespace:
|
|
76
|
+
# an unqualified ref's global namesake never serves a
|
|
77
|
+
# qualified local namesake (particlesQ016).
|
|
78
|
+
child_ns = xml_element.namespace_uri.to_s
|
|
79
|
+
expected_ns =
|
|
80
|
+
resolver.expected_namespace_for(positional).to_s
|
|
81
|
+
if positional &&
|
|
82
|
+
((child_ns.empty? && expected_ns.empty?) ||
|
|
83
|
+
child_ns == expected_ns)
|
|
84
|
+
schema_def = positional
|
|
85
|
+
end
|
|
86
|
+
end
|
|
67
87
|
rules.each do |rule|
|
|
68
88
|
argument = rule.schema_argument(schema_def, repository: resolver)
|
|
69
89
|
next if argument.nil? && !rule.runs_without_schema?
|
|
@@ -203,6 +223,23 @@ module Lutaml
|
|
|
203
223
|
end
|
|
204
224
|
end
|
|
205
225
|
|
|
226
|
+
# The child's position among its same-named siblings — the index
|
|
227
|
+
# the positional binding (duplicate same-named declarations,
|
|
228
|
+
# isDefault079) binds to. Computed on the RAW moxml nodes: the
|
|
229
|
+
# wrapper objects are not identity-stable across accessor calls
|
|
230
|
+
# (the IdUniquenessRule lesson).
|
|
231
|
+
#
|
|
232
|
+
# @return [Integer]
|
|
233
|
+
def same_name_sibling_index(element, parent)
|
|
234
|
+
raw_children = Array(parent.moxml_element.elements)
|
|
235
|
+
position = raw_children.index do |node|
|
|
236
|
+
node.equal?(element.moxml_element)
|
|
237
|
+
end
|
|
238
|
+
return 0 if position.nil?
|
|
239
|
+
|
|
240
|
+
raw_children.take(position).count { |node| node.name == element.name }
|
|
241
|
+
end
|
|
242
|
+
|
|
206
243
|
# Whether the parent's content model holds a processContents
|
|
207
244
|
# skip wildcard whose namespace range admits the child — the
|
|
208
245
|
# child subtree then escapes assessment entirely (addB125).
|
|
@@ -223,6 +260,40 @@ module Lutaml
|
|
|
223
260
|
end
|
|
224
261
|
end
|
|
225
262
|
|
|
263
|
+
# A child of an ANYTYPE element validates only against a
|
|
264
|
+
# declaration in its OWN namespace (anyType content is lax —
|
|
265
|
+
# errC007's contract); a child with no exact-namespace
|
|
266
|
+
# declaration is lax-undeclared and its subtree escapes
|
|
267
|
+
# assessment. The namespace fallback never serves this
|
|
268
|
+
# decision: a targeted schema's global is a DIFFERENT element
|
|
269
|
+
# than the unqualified child.
|
|
270
|
+
#
|
|
271
|
+
# @return [Boolean]
|
|
272
|
+
def lax_any_type_child?(parent, child, resolver)
|
|
273
|
+
return false unless parent
|
|
274
|
+
|
|
275
|
+
declaration = resolver.resolve(parent.name, parent.namespace_uri)
|
|
276
|
+
return false unless any_type_declaration?(declaration, resolver)
|
|
277
|
+
|
|
278
|
+
resolver.resolve_strict(child.name, child.namespace_uri).nil?
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Whether the declaration's effective type is xs:anyType:
|
|
282
|
+
# declared by reference, or the implicit default for a typeless
|
|
283
|
+
# declaration.
|
|
284
|
+
#
|
|
285
|
+
# @return [Boolean]
|
|
286
|
+
def any_type_declaration?(declaration, resolver)
|
|
287
|
+
return false unless
|
|
288
|
+
declaration.is_a?(Lutaml::Xml::Schema::Xsd::Element)
|
|
289
|
+
|
|
290
|
+
return true if resolver.builtin_any_type?(declaration.type.to_s)
|
|
291
|
+
|
|
292
|
+
declaration.type.to_s.empty? &&
|
|
293
|
+
declaration.complex_type.nil? &&
|
|
294
|
+
declaration.simple_type.nil?
|
|
295
|
+
end
|
|
296
|
+
|
|
226
297
|
# Handle errors that occur during rule execution
|
|
227
298
|
#
|
|
228
299
|
# @param rule [ValidationRule] The rule that failed
|
|
@@ -159,10 +159,14 @@ module Lutaml
|
|
|
159
159
|
@expected_namespaces[element]
|
|
160
160
|
end
|
|
161
161
|
|
|
162
|
+
# The namespace-EXACT resolution — no unique-name fallback. The
|
|
163
|
+
# lax anyType-content decision (errC007) and other
|
|
164
|
+
# namespace-strict consumers use it.
|
|
165
|
+
#
|
|
162
166
|
# @param name [String] local element name
|
|
163
167
|
# @param namespace_uri [String, nil] instance element namespace
|
|
164
168
|
# @return [Lutaml::Xml::Schema::Xsd::Element, nil]
|
|
165
|
-
def
|
|
169
|
+
def resolve_strict(name, namespace_uri)
|
|
166
170
|
return nil if name.nil? || name.empty?
|
|
167
171
|
|
|
168
172
|
candidates = @elements[name]
|
|
@@ -171,13 +175,33 @@ module Lutaml
|
|
|
171
175
|
exact = candidates.find do |_element, namespace, _kind|
|
|
172
176
|
namespace_matches?(namespace, namespace_uri)
|
|
173
177
|
end
|
|
174
|
-
|
|
178
|
+
exact&.first
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Whether the type reference names xs:anyType.
|
|
182
|
+
#
|
|
183
|
+
# @param reference [String]
|
|
184
|
+
# @return [Boolean]
|
|
185
|
+
def builtin_any_type?(reference)
|
|
186
|
+
parts = reference.to_s.split(":")
|
|
187
|
+
%w[xs xsd].include?(parts.first) && parts.last == "anyType"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# @param name [String] local element name
|
|
191
|
+
# @param namespace_uri [String, nil] instance element namespace
|
|
192
|
+
# @return [Lutaml::Xml::Schema::Xsd::Element, nil]
|
|
193
|
+
def resolve(name, namespace_uri)
|
|
194
|
+
exact = resolve_strict(name, namespace_uri)
|
|
195
|
+
return exact if exact
|
|
175
196
|
|
|
176
197
|
# Unique-name fallback for instances that omit namespaces even
|
|
177
198
|
# though the schema declares one. A foreign namespace never
|
|
178
199
|
# falls back.
|
|
179
200
|
return nil unless namespace_uri.to_s.empty?
|
|
180
201
|
|
|
202
|
+
candidates = @elements[name]
|
|
203
|
+
return nil if candidates.empty?
|
|
204
|
+
|
|
181
205
|
candidates.length == 1 ? candidates.first.first : nil
|
|
182
206
|
end
|
|
183
207
|
|
|
@@ -563,8 +587,92 @@ module Lutaml
|
|
|
563
587
|
element_declaration_simple?(field_decl)
|
|
564
588
|
end
|
|
565
589
|
|
|
590
|
+
# The ordered same-named inline particles of the parent's
|
|
591
|
+
# content model — the POSITIONAL binding for duplicate
|
|
592
|
+
# declarations (isDefault079: two regvalueop locals with
|
|
593
|
+
# different fixed values; the second child binds to the second
|
|
594
|
+
# particle). Returns [] unless the name appears MORE THAN ONCE
|
|
595
|
+
# and every particle is INDEXED (attempt-3's starvation: raw
|
|
596
|
+
# particles carry none of the form/ns metadata the rules
|
|
597
|
+
# assume). The walk keeps its own cycle guard — the resolver's
|
|
598
|
+
# each_particle_element memoizes visited nodes on the instance
|
|
599
|
+
# and would poison repeated walks.
|
|
600
|
+
#
|
|
601
|
+
# @param parent_declaration [Lutaml::Xml::Schema::Xsd::Element, nil]
|
|
602
|
+
# @param local_name [String]
|
|
603
|
+
# @return [Array<Lutaml::Xml::Schema::Xsd::Element>]
|
|
604
|
+
def positional_children(parent_declaration, local_name)
|
|
605
|
+
type = parent_declaration&.complex_type ||
|
|
606
|
+
resolve_type(parent_declaration)
|
|
607
|
+
return [] unless type.is_a?(Lutaml::Xml::Schema::Xsd::ComplexType)
|
|
608
|
+
|
|
609
|
+
particles = []
|
|
610
|
+
collect_named_particles(particle_for_type(type), local_name,
|
|
611
|
+
particles, {}.compare_by_identity, 0)
|
|
612
|
+
return [] if particles.length < 2
|
|
613
|
+
return [] unless particles.all? { |p| @namespaces.key?(p) }
|
|
614
|
+
|
|
615
|
+
particles
|
|
616
|
+
end
|
|
617
|
+
|
|
566
618
|
private
|
|
567
619
|
|
|
620
|
+
# Depth-first ordered collection of same-named element
|
|
621
|
+
# particles; per-call visited set (identity-keyed), group refs
|
|
622
|
+
# expanded.
|
|
623
|
+
#
|
|
624
|
+
# @return [void]
|
|
625
|
+
def collect_named_particles(node, local_name, out, visited, depth)
|
|
626
|
+
return if node.nil? || depth > 24
|
|
627
|
+
|
|
628
|
+
if node.is_a?(Array)
|
|
629
|
+
node.each do |child|
|
|
630
|
+
collect_named_particles(child, local_name, out, visited,
|
|
631
|
+
depth + 1)
|
|
632
|
+
end
|
|
633
|
+
return
|
|
634
|
+
end
|
|
635
|
+
return if visited[node]
|
|
636
|
+
|
|
637
|
+
visited[node] = true
|
|
638
|
+
|
|
639
|
+
if node.is_a?(Lutaml::Xml::Schema::Xsd::Element)
|
|
640
|
+
if node.name.to_s.split(":").last == local_name
|
|
641
|
+
out << node
|
|
642
|
+
elsif node.ref.to_s.match?(/\S/) &&
|
|
643
|
+
node.ref.to_s.split(":").last == local_name
|
|
644
|
+
global = resolve_global(node.ref.to_s.split(":").last, nil)
|
|
645
|
+
out << global if global
|
|
646
|
+
end
|
|
647
|
+
return
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
nested = CONTAINER_NESTED_KINDS[node.class]
|
|
651
|
+
nested&.each do |kind|
|
|
652
|
+
collect_named_particles(Array(node.public_send(kind)),
|
|
653
|
+
local_name, out, visited, depth + 1)
|
|
654
|
+
end
|
|
655
|
+
(CONTAINER_LEAF_KINDS[node.class] || []).each do |kind|
|
|
656
|
+
Array(node.public_send(kind)).each do |leaf|
|
|
657
|
+
next unless leaf
|
|
658
|
+
|
|
659
|
+
if leaf.is_a?(Lutaml::Xml::Schema::Xsd::Group)
|
|
660
|
+
resolved = if leaf.ref
|
|
661
|
+
resolve_group(leaf.ref.to_s
|
|
662
|
+
.split(":").last)
|
|
663
|
+
else
|
|
664
|
+
leaf
|
|
665
|
+
end
|
|
666
|
+
collect_named_particles(resolved, local_name, out, visited,
|
|
667
|
+
depth + 1)
|
|
668
|
+
elsif leaf.is_a?(Lutaml::Xml::Schema::Xsd::Element)
|
|
669
|
+
collect_named_particles(leaf, local_name, out, visited,
|
|
670
|
+
depth + 1)
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
|
|
568
676
|
# Whether a TYPE carries an identity value for a field bound to
|
|
569
677
|
# the selector node itself (a "." field): a simple type or a
|
|
570
678
|
# complex type with simple content does; complex content does not.
|
data/lib/lutaml/xsd/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lutaml-xsd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.103
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-11-
|
|
11
|
+
date: 2026-11-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: liquid
|