moxml 0.5.176 → 0.5.177
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/lib/moxml/context.rb +9 -5
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml/xsd/schema_rules.rb +30 -5
- data/lib/moxml/xsd.rb +6 -2
- data/spec/moxml/xsd_set_spec.rb +78 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 021a0d5d25cfe9e12a0a29968649a0801d0379e30b4f6aefe349d86a8959149b
|
|
4
|
+
data.tar.gz: 197a8e2c303f7fa1e29e7f25b8d64502d6c3d3179ca342af4b02dda168e7fa89
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cddcf3bb2b304e5d78779cba12b3f57514b783336642a8e40ca7d8894ba47485ef6ffff114b9f8a1430e6b9669067c86f4de2bbd53aac6d18ed8ffef52828d5f
|
|
7
|
+
data.tar.gz: 6d88eb872c4a876d9f387af3e006eb8247935ff58f70c6d3249d6b3afba7809e3485c117fbeaa3dc61103ab9858997b98c230efc870e0dac0a914971bb20e49e
|
data/lib/moxml/context.rb
CHANGED
|
@@ -214,9 +214,10 @@ module Moxml
|
|
|
214
214
|
# Compile an XSD schema from a file path — <xs:include href>
|
|
215
215
|
# resolves relative to the file's directory (the engine
|
|
216
216
|
# resolves it; reading the file into #xsd would lose that).
|
|
217
|
-
# The #452 rule index reads this document only;
|
|
218
|
-
#
|
|
219
|
-
#
|
|
217
|
+
# The #452 rule index reads this document only; a document
|
|
218
|
+
# that composes others (include/import/redefine/override)
|
|
219
|
+
# turns the strict re-checks off (#510) — included parts stay
|
|
220
|
+
# engine-validated and the index can only under-report.
|
|
220
221
|
def xsd_file(path)
|
|
221
222
|
handle = config.adapter.xsd_compile_file(path.to_s)
|
|
222
223
|
source = File.read(path.to_s)
|
|
@@ -229,7 +230,10 @@ module Moxml
|
|
|
229
230
|
# types) are visible to the head's content models — the
|
|
230
231
|
# single-document faces cannot see them (#483 item 4). The
|
|
231
232
|
# Schema's #version / SchemaRules index read the HEAD document
|
|
232
|
-
# (the first path); engine-set semantics cover the rest.
|
|
233
|
+
# (the first path); engine-set semantics cover the rest. A set
|
|
234
|
+
# is composition-shaped by contract, so the strict re-checks
|
|
235
|
+
# stay off (#510): the index under-reports instead of
|
|
236
|
+
# false-reporting components that live in a member.
|
|
233
237
|
# Adapters without a set-capable engine raise
|
|
234
238
|
# Moxml::NotImplementedError.
|
|
235
239
|
def xsd_set(*paths)
|
|
@@ -238,7 +242,7 @@ module Moxml
|
|
|
238
242
|
|
|
239
243
|
handle = config.adapter.xsd_compile_set(paths.map(&:to_s))
|
|
240
244
|
source = File.read(paths.first.to_s)
|
|
241
|
-
Moxml::XSD::Schema.new(handle, self, source)
|
|
245
|
+
Moxml::XSD::Schema.new(handle, self, source, self_contained: false)
|
|
242
246
|
end
|
|
243
247
|
|
|
244
248
|
# Compile a RELAX NG schema from source or from a file path (the
|
data/lib/moxml/version.rb
CHANGED
|
@@ -197,7 +197,7 @@ module Moxml
|
|
|
197
197
|
:attribute_default, :elements,
|
|
198
198
|
:attributes, :contents, :version,
|
|
199
199
|
:element_patterns, :attribute_patterns,
|
|
200
|
-
:substitution_members)
|
|
200
|
+
:substitution_members, :self_contained)
|
|
201
201
|
|
|
202
202
|
# Resolves a QName token against an element's in-scope
|
|
203
203
|
# bindings. node.namespaces is adapter-divergent (some
|
|
@@ -338,7 +338,7 @@ module Moxml
|
|
|
338
338
|
# Index one schema document. Returns nil when the source
|
|
339
339
|
# cannot be indexed — the engine's answer then stands alone
|
|
340
340
|
# (today's behavior).
|
|
341
|
-
def index(schema_source, context)
|
|
341
|
+
def index(schema_source, context, self_contained: nil)
|
|
342
342
|
root = context.parse(schema_source).root
|
|
343
343
|
return nil unless root&.name == "schema"
|
|
344
344
|
|
|
@@ -346,7 +346,8 @@ module Moxml
|
|
|
346
346
|
root["targetNamespace"].to_s,
|
|
347
347
|
root["elementFormDefault"] == "qualified",
|
|
348
348
|
root["attributeFormDefault"] == "qualified",
|
|
349
|
-
{}, {}, {}, schema_version(root), {}, {}, {}
|
|
349
|
+
{}, {}, {}, schema_version(root), {}, {}, {},
|
|
350
|
+
self_contained.nil? ? composition_free?(root) : self_contained
|
|
350
351
|
)
|
|
351
352
|
child_elements(root).each do |decl|
|
|
352
353
|
case decl.name
|
|
@@ -360,6 +361,24 @@ module Moxml
|
|
|
360
361
|
nil
|
|
361
362
|
end
|
|
362
363
|
|
|
364
|
+
COMPOSITION_ELEMENTS = %w[include import redefine override].freeze
|
|
365
|
+
|
|
366
|
+
# A schema document that composes other documents
|
|
367
|
+
# (include/import/redefine/override) declares only part of
|
|
368
|
+
# the compiled declaration surface in its own source — the
|
|
369
|
+
# engine resolves the members, and a strict re-check run
|
|
370
|
+
# against this index alone would answer "not declared" for
|
|
371
|
+
# components that live in a member (#510): a false report,
|
|
372
|
+
# which the one-directional contract forbids. Composition
|
|
373
|
+
# therefore turns the strict re-checks off — the index
|
|
374
|
+
# under-reports instead. Schema sets (xsd_set) are always
|
|
375
|
+
# composition-shaped: any member may carry declarations.
|
|
376
|
+
def composition_free?(root)
|
|
377
|
+
child_elements(root).none? do |decl|
|
|
378
|
+
COMPOSITION_ELEMENTS.include?(decl.name)
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
363
382
|
# The effective schema version declared at the root
|
|
364
383
|
# (#460 item 2): vc:minVersion="1.1" on <xs:schema> scopes
|
|
365
384
|
# the document to 1.1 semantics; anything else reports
|
|
@@ -606,12 +625,18 @@ module Moxml
|
|
|
606
625
|
model = index.contents[root_qname]
|
|
607
626
|
findings = []
|
|
608
627
|
findings << nil_finding(root, declaration) if declaration
|
|
609
|
-
|
|
610
|
-
|
|
628
|
+
# The strict wildcard/attribute re-checks answer "not
|
|
629
|
+
# declared" against this index's declaration sets — they
|
|
630
|
+
# vouch only when the index saw the whole declaration
|
|
631
|
+
# surface (no composition, #510).
|
|
632
|
+
if model && index.self_contained
|
|
611
633
|
child_elements(root).each do |child|
|
|
612
634
|
findings.concat(child_findings(child, model, index))
|
|
613
635
|
end
|
|
614
636
|
end
|
|
637
|
+
if index.self_contained
|
|
638
|
+
findings.concat(attribute_findings(root, model, index))
|
|
639
|
+
end
|
|
615
640
|
findings.compact
|
|
616
641
|
end
|
|
617
642
|
|
data/lib/moxml/xsd.rb
CHANGED
|
@@ -96,11 +96,15 @@ module Moxml
|
|
|
96
96
|
"schema released (deterministic drop); compile a new one"
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
def initialize(handle, context, schema_source = nil
|
|
99
|
+
def initialize(handle, context, schema_source = nil,
|
|
100
|
+
self_contained: nil)
|
|
100
101
|
@handle = handle
|
|
101
102
|
@context = context
|
|
102
103
|
@rules_index =
|
|
103
|
-
|
|
104
|
+
if schema_source
|
|
105
|
+
SchemaRules.index(schema_source, context,
|
|
106
|
+
self_contained: self_contained)
|
|
107
|
+
end
|
|
104
108
|
assert_adapter_matches_handle!
|
|
105
109
|
end
|
|
106
110
|
|
data/spec/moxml/xsd_set_spec.rb
CHANGED
|
@@ -82,6 +82,84 @@ RSpec.describe "Schema-set compilation" do
|
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
# #510: the strict re-check answers "not declared" against the
|
|
86
|
+
# head document's own declaration index; composition (a set, or a
|
|
87
|
+
# single document carrying include/import/redefine/override)
|
|
88
|
+
# means declarations may live in a member the index never saw —
|
|
89
|
+
# the re-check must stay silent (under-report, never
|
|
90
|
+
# false-report) and let the engine's set-wide answer stand.
|
|
91
|
+
describe "strict re-check across composed schemas (#510)" do
|
|
92
|
+
def write_wildcard_set(dir)
|
|
93
|
+
File.write(File.join(dir, "headw.xsd"), <<~XSD)
|
|
94
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
95
|
+
xmlns="urn:W" targetNamespace="urn:W">
|
|
96
|
+
<xs:import namespace="urn:D" schemaLocation="decl.xsd"/>
|
|
97
|
+
<xs:element name="foo">
|
|
98
|
+
<xs:complexType>
|
|
99
|
+
<xs:sequence>
|
|
100
|
+
<xs:any namespace="##other" processContents="strict"/>
|
|
101
|
+
</xs:sequence>
|
|
102
|
+
</xs:complexType>
|
|
103
|
+
</xs:element>
|
|
104
|
+
</xs:schema>
|
|
105
|
+
XSD
|
|
106
|
+
File.write(File.join(dir, "decl.xsd"), <<~XSD)
|
|
107
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
108
|
+
xmlns="urn:D" targetNamespace="urn:D">
|
|
109
|
+
<xs:element name="bar" type="xs:string"/>
|
|
110
|
+
</xs:schema>
|
|
111
|
+
XSD
|
|
112
|
+
[File.join(dir, "headw.xsd"), File.join(dir, "decl.xsd")]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def wildcard_instance
|
|
116
|
+
'<foo xmlns="urn:W" xmlns:d="urn:D"><d:bar>hi</d:bar></foo>'
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "does not false-report a member-declared admission on a set" do
|
|
120
|
+
skip "requires the leptris compile_set face (binding 1.9.386.0+)" unless
|
|
121
|
+
set_capable?
|
|
122
|
+
|
|
123
|
+
Dir.mktmpdir do |dir|
|
|
124
|
+
paths = write_wildcard_set(dir)
|
|
125
|
+
schema = ctx.xsd_set(*paths)
|
|
126
|
+
expect(schema.validate(wildcard_instance)).to be_empty
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "does not false-report on a single composing document" do
|
|
131
|
+
Dir.mktmpdir do |dir|
|
|
132
|
+
write_wildcard_set(dir)
|
|
133
|
+
schema = ctx.xsd_file(File.join(dir, "headw.xsd"))
|
|
134
|
+
expect(schema.validate(wildcard_instance)).to be_empty
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "keeps the re-check on a self-contained schema" do
|
|
139
|
+
Dir.mktmpdir do |dir|
|
|
140
|
+
path = File.join(dir, "solo.xsd")
|
|
141
|
+
File.write(path, <<~XSD)
|
|
142
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
|
143
|
+
xmlns="urn:S" targetNamespace="urn:S">
|
|
144
|
+
<xs:element name="solo">
|
|
145
|
+
<xs:complexType>
|
|
146
|
+
<xs:sequence>
|
|
147
|
+
<xs:any namespace="##other" processContents="strict"/>
|
|
148
|
+
</xs:sequence>
|
|
149
|
+
</xs:complexType>
|
|
150
|
+
</xs:element>
|
|
151
|
+
</xs:schema>
|
|
152
|
+
XSD
|
|
153
|
+
schema = ctx.xsd_file(path)
|
|
154
|
+
errors = schema.validate(
|
|
155
|
+
'<solo xmlns="urn:S"><u:x xmlns:u="urn:U"/></solo>',
|
|
156
|
+
)
|
|
157
|
+
expect(errors.first.message)
|
|
158
|
+
.to include("matches a strict wildcard but is not declared")
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
85
163
|
it "raises on an empty set" do
|
|
86
164
|
expect { ctx.xsd_set }.to raise_error(ArgumentError)
|
|
87
165
|
end
|