lutaml-xsd 1.2.76 → 1.2.78
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 +4 -4
- data/Gemfile.lock +2 -2
- data/TODO.conformance.md +40 -12
- data/lib/lutaml/xsd/validation/rules/attribute_validation_rule.rb +39 -2
- data/lib/lutaml/xsd/validation/rules/occurrence_validation_rule.rb +25 -13
- data/lib/lutaml/xsd/validation/schema_definition_resolver.rb +56 -1
- data/lib/lutaml/xsd/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 22d795e689f88ccef5f61459e717e04bafc7eaf5504b080a6062a59d9501a86e
|
|
4
|
+
data.tar.gz: fb39b92dc122c263bf6b144c70d7f6eaee7841209f8d2ad8a013daa540c13f5c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 311267aaa35718e4f3c149ed3d7e7f14eda7bee3a077ca39c6c5c4041ca70184bd4aa458c2680ed435295bbe8460bf0b1b96ce77d473225062e5afa6439cc353
|
|
7
|
+
data.tar.gz: 36edcae8faa4d6062edc3f873cc34e0c67c01c156089c1517ed21cb265df5e66729ca5588264eb856476705f62e59879c3bf47aed112497b97f5b16c17475d23
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
lutaml-xsd (1.2.
|
|
4
|
+
lutaml-xsd (1.2.78)
|
|
5
5
|
liquid (>= 4.0, < 6.0)
|
|
6
6
|
lutaml-model (~> 0.8.123)
|
|
7
7
|
lutaml-store (~> 0.3)
|
|
@@ -264,7 +264,7 @@ CHECKSUMS
|
|
|
264
264
|
liquid (5.14.0) sha256=e1020c2b2ee58c7a4d3bfdc7a331537bd27a783353748bff0bf27c6ac0c17065
|
|
265
265
|
lutaml-model (0.8.155) sha256=3d90f2fb4fdf41a42d4a05b62b3f6644b433070b82291a9371deaa8e68a1e02d
|
|
266
266
|
lutaml-store (0.3.2) sha256=9c455dbab32b4c635c48a27213f6f56fda191731c4574eb6187184ba0588a672
|
|
267
|
-
lutaml-xsd (1.2.
|
|
267
|
+
lutaml-xsd (1.2.78)
|
|
268
268
|
memo_wise (1.13.0) sha256=30220c38c4cef410849bc73553c58664dc2c91c6379e4a1df22aea02358b716b
|
|
269
269
|
moxml (0.6.1) sha256=5b7677258bbad372f0725a421f8adeae37b65d6f7871da2747e2c1906cdac7ea
|
|
270
270
|
nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
|
data/TODO.conformance.md
CHANGED
|
@@ -120,21 +120,21 @@ pinned commit) is measured via `rake conformance:w3c`:
|
|
|
120
120
|
|
|
121
121
|
| mode | pass-rate |
|
|
122
122
|
|---|---|
|
|
123
|
-
| pipeline |
|
|
123
|
+
| pipeline | 4565/4696 (97.2%) |
|
|
124
124
|
|
|
125
125
|
(2026-11-02, bundled-stack measurement on main with the escape,
|
|
126
126
|
hint-following, pattern-alternative, identity-crash, engine-set,
|
|
127
127
|
engine-refresh, IC value-space, IC field-resolution, facade-silence,
|
|
128
|
-
regex-semantics, redefine-refresh, gmonth-refresh, digit-vintage
|
|
129
|
-
stgh-refresh rounds; moxml
|
|
130
|
-
owner — the 0.6 line drops
|
|
131
|
-
conformance-neutral), lutaml-model
|
|
132
|
-
1.9.401.0.) Same-stack comparison: 1.2.43
|
|
133
|
-
4039 (86.0%) → 4090 (87.1%) → 4360 (92.8%,
|
|
134
|
-
(93.9%) → 4430 (94.3%) → 4435 (94.4%) →
|
|
135
|
-
|
|
136
|
-
(96.
|
|
137
|
-
baseline. The escapes round (PR #197 — \d→\p{Nd},
|
|
128
|
+
regex-semantics, redefine-refresh, gmonth-refresh, digit-vintage,
|
|
129
|
+
stgh-refresh, group-ref and attribute-group-redefine rounds; moxml
|
|
130
|
+
0.6.1 (gemspec floor `~> 0.6.0` per the owner — the 0.6 line drops
|
|
131
|
+
the Opal surface; measured conformance-neutral), lutaml-model
|
|
132
|
+
0.8.155, engine leptris 1.9.401.0.) Same-stack comparison: 1.2.43
|
|
133
|
+
baseline 3961 (84.3%) → 4039 (86.0%) → 4090 (87.1%) → 4360 (92.8%,
|
|
134
|
+
lockfile refresh) → 4411 (93.9%) → 4430 (94.3%) → 4435 (94.4%) →
|
|
135
|
+
4436 (94.5%) → 4439 (94.5%) → 4454 (94.9%) → 4495 (95.7%) → 4524
|
|
136
|
+
(96.3%) → 4534 (96.6%) → 4540 (96.7%) → 4542 (96.7%) → 4546 (96.8%)
|
|
137
|
+
→ 4557 (97.0%) → 4565 (97.2%), +604 net over the 1.2.43 baseline. The escapes round (PR #197 — \d→\p{Nd},
|
|
138
138
|
\w/\W/\s to their XSD value spaces) collapses Regex 120→69;
|
|
139
139
|
same-step pattern facets now behave as alternatives and
|
|
140
140
|
whitespace-only text reaches the facets intact (PR #200), Regex
|
|
@@ -242,7 +242,8 @@ moxml 0.5.170 + lutaml-model 0.8.147) → 93.9% (escape + hint rounds)
|
|
|
242
242
|
4439) → 94.9% (IC field-resolution round PR #206, 4454) → 95.7%
|
|
243
243
|
(facade-silence dep refresh, moxml 0.5.177, 4495) → 96.3% (regex
|
|
244
244
|
semantics round PR #208, 4524) → 96.6% (redefine refresh, leptris
|
|
245
|
-
1.9.396/1.9.397, 4534).
|
|
245
|
+
1.9.396/1.9.397, 4534) → 96.8% (stG/stH refresh, leptris 1.9.401,
|
|
246
|
+
4546) → 97.0% (group-ref round PR #217, 4557). Failure
|
|
246
247
|
concentration (the work queue, largest first):
|
|
247
248
|
|
|
248
249
|
- `Regex_w3c` (131) — decomposed by error source (2026-10-25): the
|
|
@@ -344,6 +345,33 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
|
|
|
344
345
|
(stG010/012, stH005/007); SimpleType 10→6; suite 4546/4696
|
|
345
346
|
(96.8%), zero regressions. #1936 remainder: reZ char-reference
|
|
346
347
|
shapes, reT51 \D vintage; plus moxml#510 addB116 straggler.
|
|
348
|
+
- GROUP-REF ROUND (2026-11-02, PR #217): +11 Group cases (19→8,
|
|
349
|
+
suite 4557/4696 = 97.0%). TWO Ruby defects: (a) `particle_for_type`
|
|
350
|
+
read sequence/choice/all from extension and restriction bodies but
|
|
351
|
+
NOT `group` — a derivation body that is a bare group reference
|
|
352
|
+
compiled to NO content model and the walk enforced nothing
|
|
353
|
+
(groupG/groupH class); (b) `composite_capacity` decided sum-vs-max
|
|
354
|
+
from the PARTICLE's class — for a Group ref it always took the max
|
|
355
|
+
branch even when the group's declaration is a SEQUENCE whose
|
|
356
|
+
members' capacities must ADD (groupH002: one branch of x1+x2 was
|
|
357
|
+
counted as two choice occurrences). Neighbors verified identical;
|
|
358
|
+
zero regressions. Group remainder: groupB009/010 + groupO004
|
|
359
|
+
(false-reject class), groupH008/J003/006/008/L008 under-detections
|
|
360
|
+
(choice-of-group capacity depth).
|
|
361
|
+
- ATTRIBUTE-GROUP-REDEFINE ROUND (2026-11-02, PR #218): +8 net
|
|
362
|
+
(AttributeGroup 17→11, Schema 14→12, Attribute 10→9; suite
|
|
363
|
+
4557→4565 = 97.2%). lutaml-model does NOT chase xs:redefine
|
|
364
|
+
targets — the original document was never parsed, so the
|
|
365
|
+
redefined group's self-ref hook had nothing to hook to and
|
|
366
|
+
expansions truncated at the cycle guard. The resolver now chases
|
|
367
|
+
the redefine target itself (relative to the defining file, via
|
|
368
|
+
the repository's source path), indexes it, keeps the ORIGINAL
|
|
369
|
+
declaration as the hook target, and expands the redefining body
|
|
370
|
+
with the self-ref resolved to that original (attgC007/attgD036).
|
|
371
|
+
Wildcards nested in attributeGroup DECLARATIONS reach types
|
|
372
|
+
through the group's resolution (attgD019). All remaining
|
|
373
|
+
AttributeGroup failures are ENGINE-only strict re-checks on
|
|
374
|
+
composed shapes (the moxml#510 thread).
|
|
347
375
|
- REGEX SEMANTICS ROUND (2026-10-31, PR #208): \w/\W now carry their
|
|
348
376
|
Appendix F complements (\w = [^\p{P}\p{Z}\p{C}], class interiors
|
|
349
377
|
via the exact positive partition L/M/N/S), \I/\C complements added
|
|
@@ -268,14 +268,23 @@ module Lutaml
|
|
|
268
268
|
return [] if depth > 5
|
|
269
269
|
return [] unless group
|
|
270
270
|
|
|
271
|
+
own = (group.name || group.ref).to_s.split(":").last
|
|
271
272
|
attrs = Array(group.attribute)
|
|
272
273
|
|
|
273
274
|
# An attributeGroup may reference other attributeGroups —
|
|
274
|
-
# their declarations flow into the expansion (attgD004).
|
|
275
|
+
# their declarations flow into the expansion (attgD004). A
|
|
276
|
+
# reference to the group's OWN name inside an xs:redefine
|
|
277
|
+
# body is the §4.2.2 hook to the ORIGINAL definition.
|
|
275
278
|
Array(group.attribute_group).each do |nested_ref|
|
|
276
279
|
local = (nested_ref.ref || nested_ref.name).to_s
|
|
277
280
|
.split(":").last
|
|
278
|
-
declaration =
|
|
281
|
+
declaration =
|
|
282
|
+
if !local.empty? && local == own &&
|
|
283
|
+
repository&.redefined_original_for(local)
|
|
284
|
+
repository.redefined_original_for(local)
|
|
285
|
+
else
|
|
286
|
+
repository&.resolve_attribute_group(local)
|
|
287
|
+
end
|
|
279
288
|
next unless declaration
|
|
280
289
|
|
|
281
290
|
attrs.concat(expand_attribute_group(declaration, repository,
|
|
@@ -889,10 +898,15 @@ module Lutaml
|
|
|
889
898
|
complex_type_wildcard_support?
|
|
890
899
|
wildcards << complex_wildcard if complex_wildcard
|
|
891
900
|
|
|
901
|
+
# A wildcard nested in an attributeGroup DECLARATION reaches
|
|
902
|
+
# the type only through the group's resolution — the type's
|
|
903
|
+
# ref particle carries no children of its own (attgD019).
|
|
892
904
|
Array(schema_def.attribute_group).each do |group|
|
|
893
905
|
Array(group.any_attribute).each do |wildcard|
|
|
894
906
|
wildcards << wildcard
|
|
895
907
|
end
|
|
908
|
+
|
|
909
|
+
collect_group_wildcards(group, repository, wildcards, 0)
|
|
896
910
|
end
|
|
897
911
|
|
|
898
912
|
CONTENT_KINDS.each do |content_kind|
|
|
@@ -916,6 +930,29 @@ module Lutaml
|
|
|
916
930
|
wildcards
|
|
917
931
|
end
|
|
918
932
|
|
|
933
|
+
# The wildcards of an attributeGroup reference's DECLARATION,
|
|
934
|
+
# following nested attributeGroup refs (depth-guarded).
|
|
935
|
+
#
|
|
936
|
+
# @return [void]
|
|
937
|
+
def collect_group_wildcards(group, repository, wildcards, depth)
|
|
938
|
+
return if depth > 5
|
|
939
|
+
|
|
940
|
+
local = (group.ref || group.name).to_s.split(":").last
|
|
941
|
+
return if local.to_s.empty?
|
|
942
|
+
|
|
943
|
+
declaration = repository&.resolve_attribute_group(local)
|
|
944
|
+
return unless declaration
|
|
945
|
+
|
|
946
|
+
Array(declaration.any_attribute).each do |wildcard|
|
|
947
|
+
wildcards << wildcard
|
|
948
|
+
end
|
|
949
|
+
|
|
950
|
+
Array(declaration.attribute_group).each do |nested|
|
|
951
|
+
collect_group_wildcards(nested, repository, wildcards,
|
|
952
|
+
depth + 1)
|
|
953
|
+
end
|
|
954
|
+
end
|
|
955
|
+
|
|
919
956
|
# The named base type of the derivation shape, when present.
|
|
920
957
|
#
|
|
921
958
|
# @return [Lutaml::Xml::Schema::Xsd::ComplexType, nil]
|
|
@@ -501,24 +501,36 @@ module Lutaml
|
|
|
501
501
|
end
|
|
502
502
|
|
|
503
503
|
def composite_capacity(particle, repository, depth)
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
504
|
+
# The CONTAINER's kind decides aggregation: a group whose
|
|
505
|
+
# declaration is a sequence ADDS its members' capacities, a
|
|
506
|
+
# choice takes the largest — deciding from the ref particle
|
|
507
|
+
# itself always maxed (groupH class).
|
|
508
|
+
children, aggregate =
|
|
509
|
+
if particle.is_a?(Lutaml::Xml::Schema::Xsd::Group)
|
|
510
|
+
container = expand_group_container(particle,
|
|
511
|
+
repository).first
|
|
512
|
+
if container
|
|
513
|
+
[choice_alternatives(container),
|
|
514
|
+
container_choice?(container) ? :max : :sum]
|
|
515
|
+
else
|
|
516
|
+
[[], :max]
|
|
517
|
+
end
|
|
518
|
+
else
|
|
519
|
+
[choice_alternatives(particle),
|
|
520
|
+
particle.is_a?(Lutaml::Xsd::Sequence) ? :sum : :max]
|
|
521
|
+
end
|
|
512
522
|
caps = children.map do |child|
|
|
513
523
|
branch_capacity(child, repository, depth + 1)
|
|
514
524
|
end
|
|
515
525
|
return :unbounded if caps.include?(:unbounded)
|
|
516
526
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
527
|
+
aggregate == :sum ? caps.sum : (caps.max || 0)
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
# @return [Boolean]
|
|
531
|
+
def container_choice?(container)
|
|
532
|
+
container.is_a?(Lutaml::Xsd::Choice) ||
|
|
533
|
+
container.is_a?(Lutaml::Xml::Schema::Xsd::Choice)
|
|
522
534
|
end
|
|
523
535
|
|
|
524
536
|
# Choice alternatives are particles of any kind.
|
|
@@ -49,6 +49,7 @@ module Lutaml
|
|
|
49
49
|
@named_types = {}
|
|
50
50
|
@attributes = Hash.new { |hash, key| hash[key] = [] }
|
|
51
51
|
@attribute_groups = {}
|
|
52
|
+
@redefined_originals = {}
|
|
52
53
|
@elements = index_elements
|
|
53
54
|
end
|
|
54
55
|
|
|
@@ -100,6 +101,16 @@ module Lutaml
|
|
|
100
101
|
@attribute_groups[local_name]
|
|
101
102
|
end
|
|
102
103
|
|
|
104
|
+
# The pre-redefinition declaration of an attributeGroup that an
|
|
105
|
+
# xs:redefine replaced — the target of the redefining body's
|
|
106
|
+
# self-reference hook.
|
|
107
|
+
#
|
|
108
|
+
# @param local_name [String]
|
|
109
|
+
# @return [Object, nil]
|
|
110
|
+
def redefined_original_for(local_name)
|
|
111
|
+
@redefined_originals[local_name]
|
|
112
|
+
end
|
|
113
|
+
|
|
103
114
|
# Owner schema's target namespace for a resolved declaration
|
|
104
115
|
# (parsed element models carry no owner-schema link).
|
|
105
116
|
#
|
|
@@ -428,8 +439,12 @@ module Lutaml
|
|
|
428
439
|
nil
|
|
429
440
|
when Lutaml::Xml::Schema::Xsd::ExtensionComplexContent,
|
|
430
441
|
Lutaml::Xml::Schema::Xsd::RestrictionComplexContent
|
|
442
|
+
# A derivation body may be a bare group reference — the
|
|
443
|
+
# ref's own minOccurs/maxOccurs govern the expanded model
|
|
444
|
+
# (groupG/groupH class).
|
|
431
445
|
Array(type.sequence).first ||
|
|
432
|
-
Array(type.choice).first || Array(type.all).first
|
|
446
|
+
Array(type.choice).first || Array(type.all).first ||
|
|
447
|
+
Array(type.group).first
|
|
433
448
|
end
|
|
434
449
|
end
|
|
435
450
|
|
|
@@ -534,6 +549,46 @@ module Lutaml
|
|
|
534
549
|
|
|
535
550
|
index_schema(index, nested)
|
|
536
551
|
end
|
|
552
|
+
|
|
553
|
+
# xs:redefine replaces an attributeGroup with a body whose
|
|
554
|
+
# self-reference is the §4.2.2 hook to the ORIGINAL
|
|
555
|
+
# definition. lutaml-model does NOT chase the redefine
|
|
556
|
+
# target, so the original document is parsed here (relative
|
|
557
|
+
# to the defining file) and indexed; the original
|
|
558
|
+
# declaration is kept for that hook and the redefining body
|
|
559
|
+
# indexed under the name (attgC007/attgD036). Runs after the
|
|
560
|
+
# nested descent so included declarations are already in.
|
|
561
|
+
Array(schema.redefine).each do |red|
|
|
562
|
+
target_path = nil
|
|
563
|
+
base = begin
|
|
564
|
+
File.dirname(@repository.source_path_for(schema))
|
|
565
|
+
rescue StandardError
|
|
566
|
+
nil
|
|
567
|
+
end
|
|
568
|
+
if base && red.schema_path.to_s.match?(/\S/)
|
|
569
|
+
candidate = File.expand_path(red.schema_path.to_s, base)
|
|
570
|
+
target_path = candidate if File.exist?(candidate)
|
|
571
|
+
end
|
|
572
|
+
if target_path
|
|
573
|
+
begin
|
|
574
|
+
target = Lutaml::Xml::Schema::Xsd.parse(
|
|
575
|
+
File.read(target_path), location: target_path
|
|
576
|
+
)
|
|
577
|
+
index_schema(index, target, held_signatures, namespace,
|
|
578
|
+
defaults_schema)
|
|
579
|
+
rescue StandardError
|
|
580
|
+
nil
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
Array(red.attribute_group).each do |group|
|
|
584
|
+
name = group.name.to_s
|
|
585
|
+
next if name.empty?
|
|
586
|
+
|
|
587
|
+
original = @attribute_groups[name]
|
|
588
|
+
@redefined_originals[name] = original if original
|
|
589
|
+
@attribute_groups[name] = group
|
|
590
|
+
end
|
|
591
|
+
end
|
|
537
592
|
end
|
|
538
593
|
|
|
539
594
|
def index_attribute(attribute, namespace)
|
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.78
|
|
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-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: liquid
|