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 +4 -4
- data/TODO.conformance.md +54 -10
- data/lib/lutaml/xsd/conformance/w3c_suite.rb +11 -2
- data/lib/lutaml/xsd/validation/rules/attribute_validation_rule.rb +123 -16
- data/lib/lutaml/xsd/validation/rules/content_model_validation_rule.rb +2 -1
- data/lib/lutaml/xsd/validation/schema_definition_resolver.rb +76 -32
- 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: efe4fbd2d864e7cbe9218faaf7f67fc879c4e20cc32c54e04761fcee59d2d1dc
|
|
4
|
+
data.tar.gz: 3b5618daa924a8a493645bab5ea7f0408d3b9245c32695306131c1cb9a0cfeb8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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 |
|
|
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
|
|
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
|
-
|
|
|
236
|
-
|
|
|
237
|
-
|
|
|
238
|
-
|
|
|
239
|
-
|
|
|
240
|
-
|
|
|
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
|
-
|
|
|
243
|
-
|
|
|
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
|
-
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
235
|
-
local =
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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
|
|
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 '#{
|
|
619
|
+
"value '#{fixed}'",
|
|
513
620
|
location: xml_element.xpath,
|
|
514
621
|
context: {
|
|
515
622
|
attribute: xml_attr.name,
|
|
516
|
-
expected:
|
|
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 &&
|
|
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
|
-
|
|
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
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
|
|
631
|
-
|
|
632
|
-
|
|
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
|
|
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.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-
|
|
11
|
+
date: 2026-11-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: liquid
|