lutaml-xsd 1.2.81 → 1.2.83

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: 467b4c2343707af1d200289a1666d12e3ab984c438f0a29ef601d92143914562
4
- data.tar.gz: d249de5b32c7fb201c8025cf56af088bde07acb6e1f76d2cd3ae1f15bd39cf29
3
+ metadata.gz: efe4fbd2d864e7cbe9218faaf7f67fc879c4e20cc32c54e04761fcee59d2d1dc
4
+ data.tar.gz: 3b5618daa924a8a493645bab5ea7f0408d3b9245c32695306131c1cb9a0cfeb8
5
5
  SHA512:
6
- metadata.gz: 0f9c9c9c71bf3e064dd93ab6e007df3f9d90aaad2478bf77d8f7b7915804b5e8218a6d8adb97be02293560dc261ed957a6fe09af5404a30b18ee7a0d5d1a941e
7
- data.tar.gz: 539a1503358510cde20356dc3d6a0a1a2c0b9daaebf77bda9ef45bc54f45222a0eaf2d97477b05f1347b1d35dcc22742963b0fc388823217bc6cd45ceb900bdf
6
+ metadata.gz: 909c81244dd126cbbb8843fcd3a010f5da4a3c70bd325b71ed5865496cc390d101fecb6d6a4c38069b350abad064c4837328f5ee28cdcb583b4ec5e439c629da
7
+ data.tar.gz: 34a60915d85511b36be444dc6903e8f3f221e6740d3d6147fd5966c0fe82a852896dffb20fbf6253376bb78abeaa4a2717da83b4b44e644739acda1e85105c33
data/TODO.conformance.md CHANGED
@@ -120,7 +120,7 @@ pinned commit) is measured via `rake conformance:w3c`:
120
120
 
121
121
  | mode | pass-rate |
122
122
  |---|---|
123
- | pipeline | 4573/4696 (97.38%) |
123
+ | pipeline | 4585/4696 (97.64%) |
124
124
 
125
125
  (2026-11-02, bundled-stack measurement with the escape,
126
126
  hint-following, pattern-alternative, identity-crash, engine-set,
@@ -142,7 +142,9 @@ lockfile refresh) → 4411 (93.9%) → 4430 (94.3%) → 4435 (94.4%) →
142
142
  4436 (94.5%) → 4439 (94.5%) → 4454 (94.9%) → 4495 (95.7%) → 4524
143
143
  (96.3%) → 4534 (96.6%) → 4540 (96.7%) → 4542 (96.7%) → 4546 (96.8%)
144
144
  → 4557 (97.0%) → 4565 (97.2%) → 4569 (97.3%) → 4562 (drift raw) →
145
- 4563 (97.17%, ref-namespace round) → 4573 (97.38%, group-content round), +612 net over the 1.2.43 baseline. The escapes round (PR #197 — \d→\p{Nd},
145
+ 4563 (97.17%, ref-namespace round) → 4573 (97.38%, group-content
146
+ round) → 4578 (97.49%, attribute-prohibition round) → 4585 (97.64%,
147
+ multi-document round), +624 net over the 1.2.43 baseline. The escapes round (PR #197 — \d→\p{Nd},
146
148
  \w/\W/\s to their XSD value spaces) collapses Regex 120→69;
147
149
  same-step pattern facets now behave as alternatives and
148
150
  whitespace-only text reaches the facets intact (PR #200), Regex
@@ -232,15 +234,19 @@ corners.
232
234
 
233
235
  | Class | Cases | Filed |
234
236
  |---|---|---|
235
- | Facade strict re-check on composed schemas — remaining shapes (ctE019 attribute re-check, addB116 substitution admission) | ~8 | moxml#510 (+2 follow-up comments) |
236
- | Redefine self-extension drops the extension content model | 0 — FIXED in leptris 1.9.396 | leptris#1926 (closed) |
237
- | Built-in lexical tables reject valid forms (char-reference shapes; gMonth FIXED 1.9.398, \d legacy-Nd FIXED 1.9.399, stG/stH list lexicals FIXED 1.9.400/401) | ~5 | leptris#1936 |
238
- | Automaton size cap surfaces as an instance error instead of engine-inert silence | 0 — FIXED in leptris 1.9.398 | moxml#514 (follow-up to #473) |
239
- | Regex dialect remainder (engine `\d` vintage, `\p{Is...}` blocks, char-reference shapes) | ~30 | engine-side of leptris#1936 |
240
- | Empty content against a fixed element value rejected (1.9.402.0 regression — isDefault001/002/076, ctZ013a, elemQ019, stE065/066/096, particlesZ040) | 9 | leptris-rs#25 |
237
+ | Empty content against a fixed element value rejected (1.9.402.0 regression — isDefault001/002/076, ctZ013a, elemQ019, stE065/066/096, particlesZ040; attribute leg addB104, attO006) | 15 | leptris-rs#25 (+ case-list comment) |
238
+ | Content model enforced on NILLED elements (QFE1700g2, particlesIa002) | 2 | leptris-rs#26 |
239
+ | dateTime enumeration rejects timezone-equal forms (dateTime_enumeration005a/b) | 2 | leptris-rs#27 |
240
+ | "-0" rejected against nonNegativeInteger (errE002) | 1 | leptris-rs#28 |
241
+ | xsi:type override / substitution-member type binding false rejects (elemZ002, elemZ020) | 2 | leptris-rs#29 |
242
+ | Built-in lexical tables (char-reference shapes reZ003v/004v/005v/006v/006i, reK88; \D vintage reT51) | 7 | leptris/leptris#1936 (+ case-list comment) |
243
+ | Facade strict re-check on composed schemas — attributes (attgD005/019/020/021/022/025/027/029/031/033/034, attJ018) and composed type binding (schF1/G2/G7/P2) | 15 | moxml#510 (+ consolidated evidence comment) |
241
244
  | Unresolvable include/import/redefine schemaLocation raises at parse instead of warning (anyURI_a001/a002, schD7, schG8) | 4 | lutaml-model#1087 |
242
- | Strict wildcard/attribute admission on further compositions | ~5 | moxml#510 thread |
243
- | Ruby-side under-detections (Group 16, DataTypes 7, IC 6, Attribute 5, Additional 4, Particles 4, SimpleType 4, Element 1, Wildcards 1 — minus what the regex round banked) | ~60 | OURS — the remaining Ruby work queue |
245
+ | Automaton size cap surfaces as an instance error instead of engine-inert silence | 0 — FIXED in leptris 1.9.398 | moxml#514 (follow-up to #473) |
246
+ | Redefine self-extension drops the extension content model | 0 — FIXED in leptris 1.9.396 | leptris#1926 (closed) |
247
+ | Ruby-side under-detections and false rejects (Regex dialect 18 — reJ/reS/reDH disputed families excluded; DataTypes corners duration028-030/dateTime013/gMonthDay006/dtZ86723; IC idK/idZ singletons; SimpleType stZ; Wildcards wildZ013; Group/Particles stragglers; Schema schT/D10/F2/errC007; Q032 chameleon import; particlesA013/A002/Ie004/Ig003/Ob012/015/Z001; mgO006/034; attF001/attJ002/003/attLa005; isDefault079) | ~55 | OURS — the remaining Ruby work queue |
248
+
249
+ Engine-attribution census (2026-11-03): of the 123 current failures, 50 carry engine findings (all attributed above), 73 are Ruby-side.
244
250
 
245
251
  Suite history (same-stack where known): 71.8% baseline → 83.5%
246
252
  (pre-NFA) → 83.6% (NFA + guard, 1.2.41) → 84.3% (#180) → 86.0%
@@ -450,6 +456,44 @@ tuple keys, node-set field violations and absent-field rows handled, cross-eleme
450
456
  import; our index keeps them no-namespace so the four e2 refs
451
457
  mis-resolve). Zero regressions; the drift entries above remain
452
458
  (fixed-empty 9, reU6).
459
+ - ATTRIBUTE-PROHIBITION ROUND (2026-11-03): +5 Attribute (9→4,
460
+ attF001/J002/J003/Z007i under-detections + attLa005 fixed-facet;
461
+ suite 4573→4578 = 97.49%, ZERO regressions, rspec green).
462
+ use=prohibited was never enforced — instances could carry a
463
+ prohibited attribute unchecked. The declaration binds now, with
464
+ THREE suite-arbitrated exemptions for incoherent shapes: a
465
+ wildcard admitting the attribute shadows it (attZ002); fixed +
466
+ prohibited is an illegal combo treated as inert (attP031); a
467
+ prohibited member inside an attributeGroup DEFINITION is illegal
468
+ placement the suite ignores (attZ015). A derived type's OWN
469
+ declaration overrides the base chain's prohibited (attZ007v) while
470
+ a restriction body's own prohibited stands (attZ007i). A ref's
471
+ use-site fixed overlays the global declaration in the value check
472
+ (attLa005). Attribute remainder (4): attJ018 + attO009/011
473
+ (engine-silent — queue), attO006 (leptris-rs#25 attribute leg).
474
+ - MULTI-DOCUMENT ROUND (2026-11-03): +7 (Schema 12→9 — the schT3/T9/
475
+ T10 redefine trio; ComplexType 4→1, Particles 12→10, Additional
476
+ 10→9, IC 7→6 — same-namespace collision pairs; suite 4578→4585 =
477
+ 97.64%, zero regressions, rspec green). TWO defects: (a) the
478
+ conformance repository keyed documents by TARGET NAMESPACE, so two
479
+ schemaDocuments sharing a namespace silently overwrote each other
480
+ and only one survived (schT3's redefine pair, both ns-a); a
481
+ same-namespace collision now suffixes the key instead of dropping
482
+ the document — every other case keeps the production one-doc-per-
483
+ namespace semantics (a naive path-key for everything cost 25
484
+ regressions via the unique-name fallback and first-match type
485
+ lookup, caught and reverted in-round). (b) resolve_named_type now
486
+ falls back to the parsed xs:redefine target documents: types living
487
+ only in the target (schT3 b-ct/b-st) resolve for plain references;
488
+ names a redefine BODY redefines stay OFF that path (the body is the
489
+ effective type and is not resolvable here — idF/idG/idH keep the
490
+ lenient path). KNOWN GAPS left open: schA1/schQ1/schD10/schF2
491
+ (hint-composition with same-local-name ct-A across namespaces —
492
+ per-namespace type binding), full type-redefine body semantics
493
+ (the body as effective type with the self-base hook — a
494
+ lutaml-model Redefine model shape study). Remaining Schema 9:
495
+ schA1/Q1/D10/F2 (ours), schD7/G8 (lutaml-model#1087),
496
+ schF1/G2/G7/P2 (moxml#510 composed bindings).
453
497
  - REGEX SEMANTICS ROUND (2026-10-31, PR #208): \w/\W now carry their
454
498
  Appendix F complements (\w = [^\p{P}\p{Z}\p{C}], class interiors
455
499
  via the exact positive partition L/M/N/S), \I/\C complements added
@@ -154,8 +154,17 @@ module Lutaml
154
154
  test_case.schema_paths.each do |path|
155
155
  schema = Lutaml::Xml::Schema::Xsd.parse(File.read(path),
156
156
  location: path)
157
- key = schema.target_namespace if
158
- schema.target_namespace.to_s.match?(/\S/)
157
+ # Keyed by target namespace like production, EXCEPT that a
158
+ # same-namespace collision suffixes the key instead of
159
+ # dropping the document (schT3's redefine pair both declare
160
+ # ns-a). The resolver iterates values; keys only need to
161
+ # keep every document present.
162
+ key = if schema.target_namespace.to_s.match?(/\S/)
163
+ schema.target_namespace
164
+ else
165
+ path
166
+ end
167
+ key = "#{key}##{path}" while schemas.key?(key)
159
168
  schemas[key] = schema
160
169
  locations[path] = schema
161
170
  end
@@ -94,11 +94,24 @@ module Lutaml
94
94
  resolved_attributes,
95
95
  xml_attributes, collector)
96
96
 
97
+ # Step 1b: Check prohibited attributes are absent — the
98
+ # declaration exists, its USE does not (attF001). Three
99
+ # suite-arbitrated exemptions: a wildcard that admits the
100
+ # attribute shadows the prohibition (attZ002); fixed plus
101
+ # prohibited is an illegal declaration combo and the suite
102
+ # treats the whole declaration as inert (attP031); and a
103
+ # prohibition arriving through DERIVATION is refinement
104
+ # incoherence the suite ignores (attZ007v, attZ015).
105
+ validate_prohibited_attributes(xml_element, schema_attributes,
106
+ xml_attributes, collector,
107
+ wildcards: wildcards)
108
+
97
109
  # Step 2: Validate attribute values
98
110
  validate_attribute_values(xml_element, resolved_attributes,
99
111
  xml_attributes, collector,
100
112
  repository: repository,
101
- schema_element: schema_element)
113
+ schema_element: schema_element,
114
+ raw_attrs: schema_attributes)
102
115
 
103
116
  # Step 3: Check for unexpected attributes
104
117
  validate_no_unexpected_attributes(xml_element,
@@ -209,7 +222,11 @@ module Lutaml
209
222
  # Base attributes flow through both derivations — a
210
223
  # restriction narrows them but cannot drop them (XSD 1.0
211
224
  # §3.4.2).
212
- attributes.concat(inherited_attributes(part.base, repository)) if part
225
+ if part
226
+ attributes.concat(
227
+ inherited_attributes(part, repository),
228
+ )
229
+ end
213
230
  end
214
231
 
215
232
  # Handle simple content
@@ -221,18 +238,50 @@ module Lutaml
221
238
  )
222
239
  part = Array(schema_def.simple_content.extension).first ||
223
240
  Array(schema_def.simple_content.restriction).first
224
- attributes.concat(inherited_attributes(part.base, repository)) if part
241
+ if part
242
+ attributes.concat(
243
+ inherited_attributes(part, repository),
244
+ )
245
+ end
225
246
  end
226
247
 
248
+ override_base_prohibitions(schema_def, attributes)
227
249
  attributes
228
250
  end
229
251
 
252
+ # A derived type's OWN (type-level or derivation-body)
253
+ # non-prohibited declaration for a name overrides the base
254
+ # chain's prohibited (attZ007v: the extension re-adds att1
255
+ # required over Two's prohibited). A restriction body's own
256
+ # prohibited stands against the inherited plain declaration
257
+ # (attZ007i: e2 carrying att1 is invalid).
258
+ #
259
+ # @return [void]
260
+ def override_base_prohibitions(schema_def, attributes)
261
+ own_declarations = Array(schema_def.attribute)
262
+ content = schema_def.complex_content || schema_def.simple_content
263
+ CONTENT_PART_KINDS.each do |kind|
264
+ part = content && Array(content.public_send(kind)).first
265
+ own_declarations += Array(part&.attribute) if part
266
+ end
267
+ own_names = own_declarations
268
+ .reject { |a| a.use.to_s == "prohibited" }
269
+ .map { |a| a.name.to_s }
270
+ attributes.reject! do |a|
271
+ a.use.to_s == "prohibited" &&
272
+ own_names.include?(a.name.to_s) &&
273
+ !own_declarations.include?(a)
274
+ end
275
+ end
276
+
230
277
  # The base type's attribute set flows into the derived type
231
- # through extension and restriction alike.
278
+ # through extension and restriction alike. The base resolves
279
+ # through the derivation so a redefine body's own base hooks
280
+ # to the original definition.
232
281
  #
233
282
  # @return [Array<Lutaml::Xml::Schema::Xsd::Attribute>]
234
- def inherited_attributes(base_name, repository)
235
- local = base_name.to_s.split(":").last
283
+ def inherited_attributes(part, repository)
284
+ local = part.base.to_s.split(":").last
236
285
  return [] if local.to_s.empty?
237
286
 
238
287
  base = repository&.resolve_named_type(local)
@@ -275,7 +324,11 @@ module Lutaml
275
324
  return [] unless group
276
325
 
277
326
  own = (group.name || group.ref).to_s.split(":").last
278
- attrs = Array(group.attribute)
327
+ # use=prohibited is illegal inside an attributeGroup
328
+ # DEFINITION (attZ015): the suite ignores such members.
329
+ attrs = Array(group.attribute).reject do |attr|
330
+ attr.use.to_s == "prohibited"
331
+ end
279
332
 
280
333
  # An attributeGroup may reference other attributeGroups —
281
334
  # their declarations flow into the expansion (attgD004). A
@@ -393,6 +446,44 @@ module Lutaml
393
446
  schema_attr.use == "required"
394
447
  end
395
448
 
449
+ # A prohibited attribute is DECLARED but its use is banned:
450
+ # any instance occurrence violates the schema (attF001).
451
+ #
452
+ # @return [void]
453
+ def validate_prohibited_attributes(xml_element, schema_attrs,
454
+ xml_attrs, collector,
455
+ wildcards: [])
456
+ schema_attrs.each do |schema_attr|
457
+ next unless schema_attr.use.to_s == "prohibited"
458
+ # fixed + prohibited is an illegal declaration combo
459
+ # (attP031): the suite treats the declaration as inert.
460
+ next if schema_attr.fixed
461
+
462
+ attr_name = schema_attr.name.to_s
463
+ next if attr_name.empty?
464
+
465
+ xml_attr = xml_attrs.find { |xa| xa.name == attr_name }
466
+ next unless xml_attr
467
+ next if wildcards.any? do |wildcard|
468
+ wildcard_permits_attribute?(wildcard, xml_element, xml_attr,
469
+ nil)
470
+ end
471
+
472
+ report_error(
473
+ collector,
474
+ code: "prohibited_attribute_present",
475
+ message: "Attribute '#{attr_name}' is prohibited here " \
476
+ "but present",
477
+ location: xml_element.xpath,
478
+ context: {
479
+ attribute: attr_name,
480
+ element: xml_element.name,
481
+ },
482
+ suggestion: "Remove attribute: #{attr_name}",
483
+ )
484
+ end
485
+ end
486
+
396
487
  # Validate attribute values
397
488
  #
398
489
  # @param xml_element [XmlElement] The element
@@ -402,14 +493,23 @@ module Lutaml
402
493
  # @return [void]
403
494
  def validate_attribute_values(xml_element, schema_attrs, xml_attrs,
404
495
  collector, repository: nil,
405
- schema_element: nil)
496
+ schema_element: nil, raw_attrs: [])
406
497
  xml_attrs.each do |xml_attr|
407
498
  schema_attr = find_schema_attribute(schema_attrs, xml_attr,
408
499
  repository, schema_element)
409
500
  next unless schema_attr
410
501
 
502
+ # A ref's use site may carry facets the global declaration
503
+ # lacks (attLa005: ref="x:ga1" fixed="abc" at the use
504
+ # site); the instance value is checked against them too.
505
+ use_site = raw_attrs.find do |r|
506
+ r.name == schema_attr.name ||
507
+ r.ref.to_s.split(":").last == schema_attr.name
508
+ end
411
509
  validate_attribute_value(xml_element, xml_attr, schema_attr,
412
- collector, repository: repository)
510
+ collector,
511
+ repository: repository,
512
+ use_site: use_site)
413
513
  end
414
514
  end
415
515
 
@@ -461,10 +561,11 @@ module Lutaml
461
561
  # "123").
462
562
  #
463
563
  # @return [Boolean]
464
- def fixed_value_matches?(value, schema_attr)
564
+ def fixed_value_matches?(value, schema_attr, fixed_override = nil)
565
+ fixed = fixed_override || schema_attr.fixed
465
566
  rule = attribute_whitespace_rule(schema_attr)
466
567
  canonical_lexical(value, rule) ==
467
- canonical_lexical(schema_attr.fixed, rule)
568
+ canonical_lexical(fixed, rule)
468
569
  end
469
570
 
470
571
  # @return [Symbol] :preserve, :replace or :collapse
@@ -499,21 +600,27 @@ module Lutaml
499
600
  # @param collector [ResultCollector] Result collector
500
601
  # @return [void]
501
602
  def validate_attribute_value(xml_element, xml_attr, schema_attr,
502
- collector, repository: nil)
603
+ collector, repository: nil,
604
+ use_site: nil)
503
605
  value = xml_attr.value
606
+ fixed = if use_site && !use_site.fixed.nil?
607
+ use_site.fixed
608
+ else
609
+ schema_attr.fixed
610
+ end
504
611
 
505
612
  # Check fixed value constraint
506
- if schema_attr.fixed
507
- unless fixed_value_matches?(value, schema_attr)
613
+ if fixed
614
+ unless fixed_value_matches?(value, schema_attr, fixed)
508
615
  report_error(
509
616
  collector,
510
617
  code: "fixed_attribute_value_mismatch",
511
618
  message: "Attribute '#{xml_attr.name}' must have fixed " \
512
- "value '#{schema_attr.fixed}'",
619
+ "value '#{fixed}'",
513
620
  location: xml_element.xpath,
514
621
  context: {
515
622
  attribute: xml_attr.name,
516
- expected: schema_attr.fixed,
623
+ expected: fixed,
517
624
  actual: value,
518
625
  },
519
626
  )
@@ -302,7 +302,8 @@ module Lutaml
302
302
  restriction = Array(content.restriction).first
303
303
  if extension
304
304
  base_local = extension.base.to_s.split(":").last
305
- base_type = base_local && repository&.resolve_named_type(base_local)
305
+ base_type = base_local &&
306
+ repository&.resolve_named_type(base_local)
306
307
  particles = type_particles(base_type, repository, seen) +
307
308
  particles
308
309
  COMPLEX_PARTICLE_KINDS.each do |kind|
@@ -50,6 +50,14 @@ module Lutaml
50
50
  @attributes = Hash.new { |hash, key| hash[key] = [] }
51
51
  @attribute_groups = {}
52
52
  @redefined_originals = {}
53
+ # Parsed xs:redefine target documents: their named types back
54
+ # the redefined bodies (schT3: b-ct/b-st live in the target,
55
+ # which the repository does not hold). Names a redefine BODY
56
+ # redefines are NOT served from the target: the body is the
57
+ # effective type and is not resolvable here, so those keep
58
+ # the lenient unresolvable path (idF/idG/idH class).
59
+ @redefined_targets = []
60
+ @redefined_body_names = []
53
61
  @elements = index_elements
54
62
  end
55
63
 
@@ -200,18 +208,29 @@ module Lutaml
200
208
 
201
209
  result = nil
202
210
  schemas.each do |schema|
203
- found = Array(schema.complex_type).find do |ct|
204
- ct.name == local_name
205
- end
206
- found ||= Array(schema.simple_type).find do |st|
207
- st.name == local_name
208
- end
209
- result = found || find_nested_named_type(local_name, schema)
211
+ result = named_type_in(local_name, schema)
210
212
  break if result
211
213
  end
214
+ if result.nil? && !@redefined_body_names.include?(local_name)
215
+ @redefined_targets.each do |schema|
216
+ result = named_type_in(local_name, schema)
217
+ break if result
218
+ end
219
+ end
212
220
  @named_types[local_name] = result
213
221
  end
214
222
 
223
+ # @return [Object, nil]
224
+ def named_type_in(local_name, schema)
225
+ found = Array(schema.complex_type).find do |ct|
226
+ ct.name == local_name
227
+ end
228
+ found ||= Array(schema.simple_type).find do |st|
229
+ st.name == local_name
230
+ end
231
+ found || find_nested_named_type(local_name, schema)
232
+ end
233
+
215
234
  # Named types declared in documents reached through resolved
216
235
  # includes/imports — chameleon types (ctE018) live in a
217
236
  # no-namespace include target.
@@ -602,35 +621,60 @@ module Lutaml
602
621
  # indexed under the name (attgC007/attgD036). Runs after the
603
622
  # nested descent so included declarations are already in.
604
623
  Array(schema.redefine).each do |red|
605
- target_path = nil
606
- base = begin
607
- File.dirname(@repository.source_path_for(schema))
624
+ index_redefine(index, schema, red, held_signatures, namespace,
625
+ defaults_schema)
626
+ end
627
+ end
628
+
629
+ # xs:redefine replaces an attributeGroup with a body whose
630
+ # self-reference is the §4.2.2 hook to the ORIGINAL
631
+ # definition. lutaml-model does NOT chase the redefine
632
+ # target, so the original document is parsed here (relative
633
+ # to the defining file) and indexed; the original
634
+ # declaration is kept for that hook and the redefining body
635
+ # indexed under the name (attgC007/attgD036). Runs after the
636
+ # nested descent so included declarations are already in.
637
+ def index_redefine(index, schema, red, held_signatures, namespace,
638
+ defaults_schema)
639
+ target_path = nil
640
+ base = begin
641
+ File.dirname(@repository.source_path_for(schema))
642
+ rescue StandardError
643
+ nil
644
+ end
645
+ if base && red.schema_path.to_s.match?(/\S/)
646
+ candidate = File.expand_path(red.schema_path.to_s, base)
647
+ target_path = candidate if File.exist?(candidate)
648
+ end
649
+ if target_path
650
+ begin
651
+ target = Lutaml::Xml::Schema::Xsd.parse(
652
+ File.read(target_path), location: target_path
653
+ )
654
+ @redefined_targets << target
655
+ index_schema(index, target, held_signatures, namespace,
656
+ defaults_schema)
608
657
  rescue StandardError
609
658
  nil
610
659
  end
611
- if base && red.schema_path.to_s.match?(/\S/)
612
- candidate = File.expand_path(red.schema_path.to_s, base)
613
- target_path = candidate if File.exist?(candidate)
614
- end
615
- if target_path
616
- begin
617
- target = Lutaml::Xml::Schema::Xsd.parse(
618
- File.read(target_path), location: target_path
619
- )
620
- index_schema(index, target, held_signatures, namespace,
621
- defaults_schema)
622
- rescue StandardError
623
- nil
624
- end
625
- end
626
- Array(red.attribute_group).each do |group|
627
- name = group.name.to_s
628
- next if name.empty?
660
+ end
661
+ # Names the body redefines: served by the body (not
662
+ # resolvable here), never by the target originals.
663
+ Array(red.complex_type).each do |body|
664
+ name = body.name.to_s
665
+ @redefined_body_names << name unless name.empty?
666
+ end
667
+ Array(red.simple_type).each do |body|
668
+ name = body.name.to_s
669
+ @redefined_body_names << name unless name.empty?
670
+ end
671
+ Array(red.attribute_group).each do |group|
672
+ name = group.name.to_s
673
+ next if name.empty?
629
674
 
630
- original = @attribute_groups[name]
631
- @redefined_originals[name] = original if original
632
- @attribute_groups[name] = group
633
- end
675
+ original = @attribute_groups[name]
676
+ @redefined_originals[name] = original if original
677
+ @attribute_groups[name] = group
634
678
  end
635
679
  end
636
680
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Xsd
5
- VERSION = "1.2.81"
5
+ VERSION = "1.2.83"
6
6
  end
7
7
  end
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.81
4
+ version: 1.2.83
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-02 00:00:00.000000000 Z
11
+ date: 2026-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid