uss-xsd-engine 0.1.1 → 0.2.1
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.
- package/README.md +15 -71
- package/dist/uss-xsd-engine.esm.js +1325 -116
- package/dist/uss-xsd-engine.standalone.js +1325 -116
- package/package.json +71 -70
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* uss-xsd-engine v0.
|
|
2
|
+
* uss-xsd-engine v0.2.1
|
|
3
3
|
* (c) 2026 Bernard Mumble
|
|
4
4
|
* MIT License
|
|
5
5
|
*/
|
|
@@ -45,6 +45,10 @@ var ISSUE_CODES = {
|
|
|
45
45
|
UNKNOWN_GROUP: "UNKNOWN_GROUP",
|
|
46
46
|
UNKNOWN_ATTRIBUTE_GROUP: "UNKNOWN_ATTRIBUTE_GROUP",
|
|
47
47
|
MISSING_BASE_TYPE: "MISSING_BASE_TYPE",
|
|
48
|
+
INVALID_CONSTRAINT_SELECTOR: "INVALID_CONSTRAINT_SELECTOR",
|
|
49
|
+
INVALID_CONSTRAINT_FIELD: "INVALID_CONSTRAINT_FIELD",
|
|
50
|
+
UNKNOWN_KEY_REFERENCE: "UNKNOWN_KEY_REFERENCE",
|
|
51
|
+
DUPLICATE_CONSTRAINT_NAME: "DUPLICATE_CONSTRAINT_NAME",
|
|
48
52
|
UNSUPPORTED_FEATURE: "UNSUPPORTED_FEATURE",
|
|
49
53
|
INVALID_OCCURS_RANGE: "INVALID_OCCURS_RANGE",
|
|
50
54
|
INVALID_DEFAULT_FIXED_COMBINATION: "INVALID_DEFAULT_FIXED_COMBINATION",
|
|
@@ -61,6 +65,12 @@ var ISSUE_CODES = {
|
|
|
61
65
|
XML_VALUE_INVALID: "XML_VALUE_INVALID",
|
|
62
66
|
XML_ENUMERATION_MISMATCH: "XML_ENUMERATION_MISMATCH",
|
|
63
67
|
XML_VALUE_REQUIRED: "XML_VALUE_REQUIRED",
|
|
68
|
+
XML_KEY_VIOLATION: "XML_KEY_VIOLATION",
|
|
69
|
+
XML_KEY_NULL_VIOLATION: "XML_KEY_NULL_VIOLATION",
|
|
70
|
+
XML_KEYREF_VIOLATION: "XML_KEYREF_VIOLATION",
|
|
71
|
+
XML_UNIQUE_VIOLATION: "XML_UNIQUE_VIOLATION",
|
|
72
|
+
XML_ANY_STRICT_VALIDATION_FAILED: "XML_ANY_STRICT_VALIDATION_FAILED",
|
|
73
|
+
XML_ANYATTRIBUTE_STRICT_VALIDATION_FAILED: "XML_ANYATTRIBUTE_STRICT_VALIDATION_FAILED",
|
|
64
74
|
XML_PATTERN_MISMATCH: "XML_PATTERN_MISMATCH",
|
|
65
75
|
XML_LENGTH_MISMATCH: "XML_LENGTH_MISMATCH",
|
|
66
76
|
XML_MIN_LENGTH_VIOLATION: "XML_MIN_LENGTH_VIOLATION",
|
|
@@ -87,6 +97,9 @@ var ISSUE_CODES = {
|
|
|
87
97
|
XSD_RESTRICTION_NOT_SUBSET: "XSD_RESTRICTION_NOT_SUBSET",
|
|
88
98
|
XSD_RESTRICTION_OCCURS_WIDENED: "XSD_RESTRICTION_OCCURS_WIDENED",
|
|
89
99
|
XSD_RESTRICTION_ATTRIBUTE_WIDENED: "XSD_RESTRICTION_ATTRIBUTE_WIDENED",
|
|
100
|
+
XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE: "XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE",
|
|
101
|
+
XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE: "XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE",
|
|
102
|
+
XSD_RESTRICTION_WILDCARD_INCOMPATIBLE: "XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
|
|
90
103
|
XSD_INCLUDE_NOT_PROVIDED: "XSD_INCLUDE_NOT_PROVIDED",
|
|
91
104
|
XSD_IMPORT_NOT_PROVIDED: "XSD_IMPORT_NOT_PROVIDED",
|
|
92
105
|
XSD_INCLUDE_NAMESPACE_MISMATCH: "XSD_INCLUDE_NAMESPACE_MISMATCH",
|
|
@@ -162,6 +175,7 @@ function createEmptySchemaModel() {
|
|
|
162
175
|
},
|
|
163
176
|
importedSchemas: [],
|
|
164
177
|
roots: [],
|
|
178
|
+
identityConstraints: [],
|
|
165
179
|
references: {
|
|
166
180
|
types: [],
|
|
167
181
|
refs: [],
|
|
@@ -193,7 +207,7 @@ function normalizeUse(value) {
|
|
|
193
207
|
function createElementDecl({
|
|
194
208
|
name = null,
|
|
195
209
|
qName = null,
|
|
196
|
-
namespaceUri:
|
|
210
|
+
namespaceUri: namespaceUri4 = null,
|
|
197
211
|
typeName = null,
|
|
198
212
|
refName = null,
|
|
199
213
|
inlineType = null,
|
|
@@ -202,6 +216,7 @@ function createElementDecl({
|
|
|
202
216
|
defaultValue = null,
|
|
203
217
|
fixedValue = null,
|
|
204
218
|
nillable = false,
|
|
219
|
+
identityConstraints = [],
|
|
205
220
|
line = null,
|
|
206
221
|
column = null,
|
|
207
222
|
path = null
|
|
@@ -210,7 +225,7 @@ function createElementDecl({
|
|
|
210
225
|
kind: "element",
|
|
211
226
|
name,
|
|
212
227
|
qName,
|
|
213
|
-
namespaceUri:
|
|
228
|
+
namespaceUri: namespaceUri4,
|
|
214
229
|
typeName,
|
|
215
230
|
refName,
|
|
216
231
|
inlineType,
|
|
@@ -219,6 +234,7 @@ function createElementDecl({
|
|
|
219
234
|
defaultValue,
|
|
220
235
|
fixedValue,
|
|
221
236
|
nillable,
|
|
237
|
+
identityConstraints,
|
|
222
238
|
line,
|
|
223
239
|
column,
|
|
224
240
|
path
|
|
@@ -227,7 +243,7 @@ function createElementDecl({
|
|
|
227
243
|
function createAttributeDecl({
|
|
228
244
|
name = null,
|
|
229
245
|
qName = null,
|
|
230
|
-
namespaceUri:
|
|
246
|
+
namespaceUri: namespaceUri4 = null,
|
|
231
247
|
typeName = null,
|
|
232
248
|
refName = null,
|
|
233
249
|
inlineType = null,
|
|
@@ -242,7 +258,7 @@ function createAttributeDecl({
|
|
|
242
258
|
kind: "attribute",
|
|
243
259
|
name,
|
|
244
260
|
qName,
|
|
245
|
-
namespaceUri:
|
|
261
|
+
namespaceUri: namespaceUri4,
|
|
246
262
|
typeName,
|
|
247
263
|
refName,
|
|
248
264
|
inlineType,
|
|
@@ -257,13 +273,14 @@ function createAttributeDecl({
|
|
|
257
273
|
function createComplexTypeDecl({
|
|
258
274
|
name = null,
|
|
259
275
|
qName = null,
|
|
260
|
-
namespaceUri:
|
|
276
|
+
namespaceUri: namespaceUri4 = null,
|
|
261
277
|
content = null,
|
|
262
278
|
attributes = [],
|
|
263
279
|
derivation = { kind: null, baseTypeName: null },
|
|
264
280
|
contentModel = "complex",
|
|
265
281
|
mixed = false,
|
|
266
282
|
abstract = false,
|
|
283
|
+
identityConstraints = [],
|
|
267
284
|
line = null,
|
|
268
285
|
column = null,
|
|
269
286
|
path = null
|
|
@@ -272,13 +289,14 @@ function createComplexTypeDecl({
|
|
|
272
289
|
kind: "complexType",
|
|
273
290
|
name,
|
|
274
291
|
qName,
|
|
275
|
-
namespaceUri:
|
|
292
|
+
namespaceUri: namespaceUri4,
|
|
276
293
|
content,
|
|
277
294
|
attributes,
|
|
278
295
|
derivation,
|
|
279
296
|
contentModel,
|
|
280
297
|
mixed,
|
|
281
298
|
abstract,
|
|
299
|
+
identityConstraints,
|
|
282
300
|
line,
|
|
283
301
|
column,
|
|
284
302
|
path
|
|
@@ -287,7 +305,7 @@ function createComplexTypeDecl({
|
|
|
287
305
|
function createSimpleTypeDecl({
|
|
288
306
|
name = null,
|
|
289
307
|
qName = null,
|
|
290
|
-
namespaceUri:
|
|
308
|
+
namespaceUri: namespaceUri4 = null,
|
|
291
309
|
baseTypeName = null,
|
|
292
310
|
facets = {},
|
|
293
311
|
enumerations = [],
|
|
@@ -299,7 +317,7 @@ function createSimpleTypeDecl({
|
|
|
299
317
|
kind: "simpleType",
|
|
300
318
|
name,
|
|
301
319
|
qName,
|
|
302
|
-
namespaceUri:
|
|
320
|
+
namespaceUri: namespaceUri4,
|
|
303
321
|
baseTypeName,
|
|
304
322
|
facets,
|
|
305
323
|
enumerations,
|
|
@@ -311,7 +329,7 @@ function createSimpleTypeDecl({
|
|
|
311
329
|
function createGroupDecl({
|
|
312
330
|
name,
|
|
313
331
|
qName = null,
|
|
314
|
-
namespaceUri:
|
|
332
|
+
namespaceUri: namespaceUri4 = null,
|
|
315
333
|
content = null,
|
|
316
334
|
line = null,
|
|
317
335
|
column = null,
|
|
@@ -321,7 +339,7 @@ function createGroupDecl({
|
|
|
321
339
|
kind: "group",
|
|
322
340
|
name,
|
|
323
341
|
qName,
|
|
324
|
-
namespaceUri:
|
|
342
|
+
namespaceUri: namespaceUri4,
|
|
325
343
|
content,
|
|
326
344
|
line,
|
|
327
345
|
column,
|
|
@@ -331,7 +349,7 @@ function createGroupDecl({
|
|
|
331
349
|
function createAttributeGroupDecl({
|
|
332
350
|
name,
|
|
333
351
|
qName = null,
|
|
334
|
-
namespaceUri:
|
|
352
|
+
namespaceUri: namespaceUri4 = null,
|
|
335
353
|
attributes = [],
|
|
336
354
|
line = null,
|
|
337
355
|
column = null,
|
|
@@ -341,7 +359,7 @@ function createAttributeGroupDecl({
|
|
|
341
359
|
kind: "attributeGroup",
|
|
342
360
|
name,
|
|
343
361
|
qName,
|
|
344
|
-
namespaceUri:
|
|
362
|
+
namespaceUri: namespaceUri4,
|
|
345
363
|
attributes,
|
|
346
364
|
line,
|
|
347
365
|
column,
|
|
@@ -362,6 +380,37 @@ function createAttributeGroupRef({
|
|
|
362
380
|
path
|
|
363
381
|
};
|
|
364
382
|
}
|
|
383
|
+
function createIdentityConstraint({
|
|
384
|
+
kind = null,
|
|
385
|
+
name = null,
|
|
386
|
+
qName = null,
|
|
387
|
+
namespaceUri: namespaceUri4 = null,
|
|
388
|
+
selector = null,
|
|
389
|
+
fields = [],
|
|
390
|
+
refer = null,
|
|
391
|
+
ownerName = null,
|
|
392
|
+
ownerNamespaceUri = null,
|
|
393
|
+
ownerPath = null,
|
|
394
|
+
line = null,
|
|
395
|
+
column = null,
|
|
396
|
+
path = null
|
|
397
|
+
} = {}) {
|
|
398
|
+
return {
|
|
399
|
+
kind,
|
|
400
|
+
name,
|
|
401
|
+
qName,
|
|
402
|
+
namespaceUri: namespaceUri4,
|
|
403
|
+
selector,
|
|
404
|
+
fields,
|
|
405
|
+
refer,
|
|
406
|
+
ownerName,
|
|
407
|
+
ownerNamespaceUri,
|
|
408
|
+
ownerPath,
|
|
409
|
+
line,
|
|
410
|
+
column,
|
|
411
|
+
path
|
|
412
|
+
};
|
|
413
|
+
}
|
|
365
414
|
function createSequenceNode({
|
|
366
415
|
children = [],
|
|
367
416
|
minOccurs = 1,
|
|
@@ -436,9 +485,11 @@ function createGroupRefNode({
|
|
|
436
485
|
}
|
|
437
486
|
function createAnyNode({
|
|
438
487
|
namespace = null,
|
|
439
|
-
processContents =
|
|
488
|
+
processContents = "strict",
|
|
440
489
|
minOccurs = 1,
|
|
441
490
|
maxOccurs = 1,
|
|
491
|
+
notNamespace = [],
|
|
492
|
+
notQName = [],
|
|
442
493
|
line = null,
|
|
443
494
|
column = null,
|
|
444
495
|
path = null
|
|
@@ -446,9 +497,31 @@ function createAnyNode({
|
|
|
446
497
|
return {
|
|
447
498
|
kind: "any",
|
|
448
499
|
namespace,
|
|
449
|
-
processContents,
|
|
500
|
+
processContents: processContents || "strict",
|
|
450
501
|
minOccurs,
|
|
451
502
|
maxOccurs,
|
|
503
|
+
notNamespace,
|
|
504
|
+
notQName,
|
|
505
|
+
line,
|
|
506
|
+
column,
|
|
507
|
+
path
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
function createAnyAttributeNode({
|
|
511
|
+
namespace = null,
|
|
512
|
+
processContents = "strict",
|
|
513
|
+
notNamespace = [],
|
|
514
|
+
notQName = [],
|
|
515
|
+
line = null,
|
|
516
|
+
column = null,
|
|
517
|
+
path = null
|
|
518
|
+
} = {}) {
|
|
519
|
+
return {
|
|
520
|
+
kind: "anyAttribute",
|
|
521
|
+
namespace,
|
|
522
|
+
processContents: processContents || "strict",
|
|
523
|
+
notNamespace,
|
|
524
|
+
notQName,
|
|
452
525
|
line,
|
|
453
526
|
column,
|
|
454
527
|
path
|
|
@@ -533,8 +606,8 @@ function resolveQName(schema, qName) {
|
|
|
533
606
|
namespaceUri: resolveNamespaceUri(schema, parsed.prefix)
|
|
534
607
|
};
|
|
535
608
|
}
|
|
536
|
-
function makeLookupKey(
|
|
537
|
-
return `${
|
|
609
|
+
function makeLookupKey(namespaceUri4, localName4) {
|
|
610
|
+
return `${namespaceUri4 || ""}::${localName4 || ""}`;
|
|
538
611
|
}
|
|
539
612
|
function isBuiltinType(typeName, schema = null) {
|
|
540
613
|
const q = parseQName(typeName);
|
|
@@ -550,41 +623,41 @@ function isBuiltinType(typeName, schema = null) {
|
|
|
550
623
|
function getLocalName(name) {
|
|
551
624
|
return parseQName(name).localName;
|
|
552
625
|
}
|
|
553
|
-
function lookupBucketByNamespace(bucket,
|
|
554
|
-
if (!bucket || !
|
|
555
|
-
return bucket[makeLookupKey(
|
|
626
|
+
function lookupBucketByNamespace(bucket, namespaceUri4, localName4) {
|
|
627
|
+
if (!bucket || !localName4) return null;
|
|
628
|
+
return bucket[makeLookupKey(namespaceUri4, localName4)] || null;
|
|
556
629
|
}
|
|
557
|
-
function lookupInSchemaBucket(bucketName, schema,
|
|
558
|
-
return lookupBucketByNamespace(schema?.globals?.[bucketName],
|
|
630
|
+
function lookupInSchemaBucket(bucketName, schema, namespaceUri4, localName4) {
|
|
631
|
+
return lookupBucketByNamespace(schema?.globals?.[bucketName], namespaceUri4, localName4);
|
|
559
632
|
}
|
|
560
|
-
function lookupInImportedSchemas(bucketName, schema,
|
|
561
|
-
if (!schema || !
|
|
633
|
+
function lookupInImportedSchemas(bucketName, schema, namespaceUri4, localName4, visited = /* @__PURE__ */ new Set()) {
|
|
634
|
+
if (!schema || !namespaceUri4) return null;
|
|
562
635
|
if (visited.has(schema)) return null;
|
|
563
636
|
visited.add(schema);
|
|
564
637
|
for (const importedSchema of schema.importedSchemas || []) {
|
|
565
638
|
if (!importedSchema) continue;
|
|
566
|
-
if ((importedSchema.targetNamespace || null) ===
|
|
639
|
+
if ((importedSchema.targetNamespace || null) === namespaceUri4) {
|
|
567
640
|
const direct = lookupInSchemaBucket(
|
|
568
641
|
bucketName,
|
|
569
642
|
importedSchema,
|
|
570
|
-
|
|
571
|
-
|
|
643
|
+
namespaceUri4,
|
|
644
|
+
localName4
|
|
572
645
|
);
|
|
573
646
|
if (direct) return direct;
|
|
574
647
|
}
|
|
575
648
|
const nested = lookupInImportedSchemas(
|
|
576
649
|
bucketName,
|
|
577
650
|
importedSchema,
|
|
578
|
-
|
|
579
|
-
|
|
651
|
+
namespaceUri4,
|
|
652
|
+
localName4,
|
|
580
653
|
visited
|
|
581
654
|
);
|
|
582
655
|
if (nested) return nested;
|
|
583
656
|
}
|
|
584
657
|
return null;
|
|
585
658
|
}
|
|
586
|
-
function lookupInImportedSchemasForUnprefixed(bucketName, schema,
|
|
587
|
-
if (!schema || !
|
|
659
|
+
function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName4, visited = /* @__PURE__ */ new Set()) {
|
|
660
|
+
if (!schema || !localName4) return null;
|
|
588
661
|
if (visited.has(schema)) return null;
|
|
589
662
|
visited.add(schema);
|
|
590
663
|
const targetNs = schema.targetNamespace || null;
|
|
@@ -596,14 +669,14 @@ function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName3, vi
|
|
|
596
669
|
bucketName,
|
|
597
670
|
importedSchema,
|
|
598
671
|
importedNs,
|
|
599
|
-
|
|
672
|
+
localName4
|
|
600
673
|
);
|
|
601
674
|
if (direct) return direct;
|
|
602
675
|
}
|
|
603
676
|
const nested = lookupInImportedSchemasForUnprefixed(
|
|
604
677
|
bucketName,
|
|
605
678
|
importedSchema,
|
|
606
|
-
|
|
679
|
+
localName4,
|
|
607
680
|
visited
|
|
608
681
|
);
|
|
609
682
|
if (nested) return nested;
|
|
@@ -614,24 +687,24 @@ function lookupByQName(bucketName, schema, name) {
|
|
|
614
687
|
if (!schema || !name) return null;
|
|
615
688
|
const parsed = parseQName(name);
|
|
616
689
|
const resolved = resolveQName(schema, name);
|
|
617
|
-
const
|
|
618
|
-
if (!
|
|
690
|
+
const localName4 = resolved.localName;
|
|
691
|
+
if (!localName4) return null;
|
|
619
692
|
if (parsed.prefix) {
|
|
620
693
|
const direct = lookupInSchemaBucket(
|
|
621
694
|
bucketName,
|
|
622
695
|
schema,
|
|
623
696
|
resolved.namespaceUri,
|
|
624
|
-
|
|
697
|
+
localName4
|
|
625
698
|
);
|
|
626
699
|
if (direct) return direct;
|
|
627
700
|
return lookupInImportedSchemas(
|
|
628
701
|
bucketName,
|
|
629
702
|
schema,
|
|
630
703
|
resolved.namespaceUri,
|
|
631
|
-
|
|
704
|
+
localName4
|
|
632
705
|
);
|
|
633
706
|
}
|
|
634
|
-
const noNamespace = lookupInSchemaBucket(bucketName, schema, null,
|
|
707
|
+
const noNamespace = lookupInSchemaBucket(bucketName, schema, null, localName4);
|
|
635
708
|
if (noNamespace) return noNamespace;
|
|
636
709
|
const sameSchemaNs = schema.targetNamespace || null;
|
|
637
710
|
if (sameSchemaNs !== null) {
|
|
@@ -639,13 +712,13 @@ function lookupByQName(bucketName, schema, name) {
|
|
|
639
712
|
bucketName,
|
|
640
713
|
schema,
|
|
641
714
|
sameSchemaNs,
|
|
642
|
-
|
|
715
|
+
localName4
|
|
643
716
|
);
|
|
644
717
|
if (hostNamespaceDecl) return hostNamespaceDecl;
|
|
645
718
|
const importedSameNamespaceDecl = lookupInImportedSchemasForUnprefixed(
|
|
646
719
|
bucketName,
|
|
647
720
|
schema,
|
|
648
|
-
|
|
721
|
+
localName4
|
|
649
722
|
);
|
|
650
723
|
if (importedSameNamespaceDecl) return importedSameNamespaceDecl;
|
|
651
724
|
}
|
|
@@ -773,11 +846,6 @@ function getEffectiveContent(schema, complexTypeDecl) {
|
|
|
773
846
|
|
|
774
847
|
// src/parser/buildSchemaModel.js
|
|
775
848
|
var UNSUPPORTED_NODE_FEATURES = /* @__PURE__ */ new Set([
|
|
776
|
-
"key",
|
|
777
|
-
"keyref",
|
|
778
|
-
"unique",
|
|
779
|
-
"any",
|
|
780
|
-
"anyAttribute",
|
|
781
849
|
"redefine",
|
|
782
850
|
"notation"
|
|
783
851
|
]);
|
|
@@ -840,6 +908,9 @@ function mergeGlobalsIntoSchema(targetSchema, sourceSchema, issues, createDuplic
|
|
|
840
908
|
...sourceSchema.externalRefs.imports || []
|
|
841
909
|
);
|
|
842
910
|
targetSchema.importedSchemas.push(...sourceSchema.importedSchemas || []);
|
|
911
|
+
targetSchema.identityConstraints.push(
|
|
912
|
+
...sourceSchema.identityConstraints || []
|
|
913
|
+
);
|
|
843
914
|
for (const feature of sourceSchema.usedFeatures || []) {
|
|
844
915
|
targetSchema.usedFeatures.add(feature);
|
|
845
916
|
}
|
|
@@ -892,17 +963,17 @@ function escapeRegExp(value) {
|
|
|
892
963
|
}
|
|
893
964
|
function locateNodeInSource(xsdText, lineStarts, node) {
|
|
894
965
|
if (!xsdText || !node) return { line: null, column: null };
|
|
895
|
-
const
|
|
966
|
+
const localName4 = node.localName;
|
|
896
967
|
const name = node.getAttribute("name");
|
|
897
968
|
const ref = node.getAttribute("ref");
|
|
898
969
|
const base = node.getAttribute("base");
|
|
899
970
|
const type = node.getAttribute("type");
|
|
900
971
|
const candidates = [
|
|
901
|
-
name ? `<(?:[\\w.-]+:)?${escapeRegExp(
|
|
902
|
-
ref ? `<(?:[\\w.-]+:)?${escapeRegExp(
|
|
903
|
-
base ? `<(?:[\\w.-]+:)?${escapeRegExp(
|
|
904
|
-
type ? `<(?:[\\w.-]+:)?${escapeRegExp(
|
|
905
|
-
`<(?:[\\w.-]+:)?${escapeRegExp(
|
|
972
|
+
name ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bname=(["'])${escapeRegExp(name)}\\1` : null,
|
|
973
|
+
ref ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bref=(["'])${escapeRegExp(ref)}\\1` : null,
|
|
974
|
+
base ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bbase=(["'])${escapeRegExp(base)}\\1` : null,
|
|
975
|
+
type ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\btype=(["'])${escapeRegExp(type)}\\1` : null,
|
|
976
|
+
`<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b`
|
|
906
977
|
].filter(Boolean);
|
|
907
978
|
for (const pattern of candidates) {
|
|
908
979
|
const regex = new RegExp(pattern, "m");
|
|
@@ -925,9 +996,9 @@ function buildPath(parentPath, node) {
|
|
|
925
996
|
return `${parentPath}/${kind}${qualifier}`;
|
|
926
997
|
}
|
|
927
998
|
function registerGlobal(schema, issues, bucketName, duplicateCode, decl) {
|
|
928
|
-
const
|
|
929
|
-
if (!
|
|
930
|
-
const key = makeLookupKey(decl.namespaceUri,
|
|
999
|
+
const localName4 = stripNamespacePrefix(decl.name);
|
|
1000
|
+
if (!localName4) return;
|
|
1001
|
+
const key = makeLookupKey(decl.namespaceUri, localName4);
|
|
931
1002
|
if (schema.globals[bucketName][key]) {
|
|
932
1003
|
issues.push(
|
|
933
1004
|
createIssue({
|
|
@@ -954,15 +1025,15 @@ function collectUnsupportedFeature(schema, feature) {
|
|
|
954
1025
|
schema.unsupportedFeatures.push(feature);
|
|
955
1026
|
}
|
|
956
1027
|
function collectNodeDiagnostics(schema, issues, node, path, loc) {
|
|
957
|
-
const
|
|
958
|
-
schema.usedFeatures.add(
|
|
959
|
-
if (UNSUPPORTED_NODE_FEATURES.has(
|
|
1028
|
+
const localName4 = node.localName;
|
|
1029
|
+
schema.usedFeatures.add(localName4);
|
|
1030
|
+
if (UNSUPPORTED_NODE_FEATURES.has(localName4)) {
|
|
960
1031
|
collectUnsupportedFeature(schema, {
|
|
961
|
-
feature: `xs:${
|
|
1032
|
+
feature: `xs:${localName4}`,
|
|
962
1033
|
line: loc.line,
|
|
963
1034
|
column: loc.column,
|
|
964
1035
|
path,
|
|
965
|
-
nodeKind:
|
|
1036
|
+
nodeKind: localName4,
|
|
966
1037
|
name: node.getAttribute("name") || null
|
|
967
1038
|
});
|
|
968
1039
|
}
|
|
@@ -972,7 +1043,7 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
|
|
|
972
1043
|
line: loc.line,
|
|
973
1044
|
column: loc.column,
|
|
974
1045
|
path,
|
|
975
|
-
nodeKind:
|
|
1046
|
+
nodeKind: localName4,
|
|
976
1047
|
name: node.getAttribute("name") || null
|
|
977
1048
|
});
|
|
978
1049
|
}
|
|
@@ -982,47 +1053,47 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
|
|
|
982
1053
|
line: loc.line,
|
|
983
1054
|
column: loc.column,
|
|
984
1055
|
path,
|
|
985
|
-
nodeKind:
|
|
1056
|
+
nodeKind: localName4,
|
|
986
1057
|
name: node.getAttribute("name") || node.getAttribute("ref") || null
|
|
987
1058
|
});
|
|
988
1059
|
}
|
|
989
|
-
if ((
|
|
1060
|
+
if ((localName4 === "element" || localName4 === "attribute") && node.hasAttribute("ref")) {
|
|
990
1061
|
collectReference(schema, "refs", {
|
|
991
1062
|
refName: node.getAttribute("ref"),
|
|
992
1063
|
line: loc.line,
|
|
993
1064
|
column: loc.column,
|
|
994
1065
|
path,
|
|
995
|
-
nodeKind:
|
|
1066
|
+
nodeKind: localName4,
|
|
996
1067
|
name: node.getAttribute("name") || null
|
|
997
1068
|
});
|
|
998
1069
|
}
|
|
999
|
-
if ((
|
|
1070
|
+
if ((localName4 === "extension" || localName4 === "restriction") && node.hasAttribute("base")) {
|
|
1000
1071
|
collectReference(schema, "baseTypes", {
|
|
1001
1072
|
baseTypeName: node.getAttribute("base"),
|
|
1002
1073
|
line: loc.line,
|
|
1003
1074
|
column: loc.column,
|
|
1004
1075
|
path,
|
|
1005
|
-
nodeKind:
|
|
1076
|
+
nodeKind: localName4,
|
|
1006
1077
|
name: node.getAttribute("name") || null
|
|
1007
1078
|
});
|
|
1008
1079
|
}
|
|
1009
|
-
if (
|
|
1080
|
+
if (localName4 === "group" && node.hasAttribute("ref")) {
|
|
1010
1081
|
collectReference(schema, "groupRefs", {
|
|
1011
1082
|
refName: node.getAttribute("ref"),
|
|
1012
1083
|
line: loc.line,
|
|
1013
1084
|
column: loc.column,
|
|
1014
1085
|
path,
|
|
1015
|
-
nodeKind:
|
|
1086
|
+
nodeKind: localName4,
|
|
1016
1087
|
name: node.getAttribute("name") || null
|
|
1017
1088
|
});
|
|
1018
1089
|
}
|
|
1019
|
-
if (
|
|
1090
|
+
if (localName4 === "attributeGroup" && node.hasAttribute("ref")) {
|
|
1020
1091
|
collectReference(schema, "attributeGroupRefs", {
|
|
1021
1092
|
refName: node.getAttribute("ref"),
|
|
1022
1093
|
line: loc.line,
|
|
1023
1094
|
column: loc.column,
|
|
1024
1095
|
path,
|
|
1025
|
-
nodeKind:
|
|
1096
|
+
nodeKind: localName4,
|
|
1026
1097
|
name: node.getAttribute("name") || null
|
|
1027
1098
|
});
|
|
1028
1099
|
}
|
|
@@ -1038,13 +1109,13 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
|
|
|
1038
1109
|
column: loc.column,
|
|
1039
1110
|
path,
|
|
1040
1111
|
source: "xsd",
|
|
1041
|
-
nodeKind:
|
|
1112
|
+
nodeKind: localName4,
|
|
1042
1113
|
name: node.getAttribute("name") || null,
|
|
1043
1114
|
details: { minOccurs, maxOccurs }
|
|
1044
1115
|
})
|
|
1045
1116
|
);
|
|
1046
1117
|
}
|
|
1047
|
-
if ((
|
|
1118
|
+
if ((localName4 === "element" || localName4 === "attribute") && node.hasAttribute("default") && node.hasAttribute("fixed")) {
|
|
1048
1119
|
issues.push(
|
|
1049
1120
|
createIssue({
|
|
1050
1121
|
code: ISSUE_CODES.INVALID_DEFAULT_FIXED_COMBINATION,
|
|
@@ -1054,7 +1125,7 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
|
|
|
1054
1125
|
column: loc.column,
|
|
1055
1126
|
path,
|
|
1056
1127
|
source: "xsd",
|
|
1057
|
-
nodeKind:
|
|
1128
|
+
nodeKind: localName4,
|
|
1058
1129
|
name: node.getAttribute("name") || node.getAttribute("ref") || null,
|
|
1059
1130
|
details: {
|
|
1060
1131
|
defaultValue: node.getAttribute("default"),
|
|
@@ -1135,11 +1206,11 @@ function parseSimpleType(node, xsdText, lineStarts, parentPath, schema, issues)
|
|
|
1135
1206
|
enumerations = parsed.enumerations;
|
|
1136
1207
|
}
|
|
1137
1208
|
const qName = node.getAttribute("name");
|
|
1138
|
-
const
|
|
1209
|
+
const namespaceUri4 = schema.targetNamespace || null;
|
|
1139
1210
|
return createSimpleTypeDecl({
|
|
1140
1211
|
name: qName ? parseQName(qName).localName : null,
|
|
1141
1212
|
qName,
|
|
1142
|
-
namespaceUri:
|
|
1213
|
+
namespaceUri: namespaceUri4,
|
|
1143
1214
|
baseTypeName,
|
|
1144
1215
|
facets,
|
|
1145
1216
|
enumerations,
|
|
@@ -1164,11 +1235,11 @@ function parseAttribute(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
|
1164
1235
|
issues
|
|
1165
1236
|
) : null;
|
|
1166
1237
|
const qName = node.getAttribute("name");
|
|
1167
|
-
const
|
|
1238
|
+
const namespaceUri4 = getDeclarationNamespaceUri(schema, node, "attribute");
|
|
1168
1239
|
return createAttributeDecl({
|
|
1169
1240
|
name: qName ? parseQName(qName).localName : null,
|
|
1170
1241
|
qName,
|
|
1171
|
-
namespaceUri:
|
|
1242
|
+
namespaceUri: namespaceUri4,
|
|
1172
1243
|
typeName: node.getAttribute("type"),
|
|
1173
1244
|
refName: node.getAttribute("ref"),
|
|
1174
1245
|
inlineType,
|
|
@@ -1209,6 +1280,10 @@ function parseAttributesContainer(nodes, xsdText, lineStarts, parentPath, schema
|
|
|
1209
1280
|
issues
|
|
1210
1281
|
)
|
|
1211
1282
|
);
|
|
1283
|
+
} else if (child.localName === "anyAttribute") {
|
|
1284
|
+
attributes.push(
|
|
1285
|
+
parseAnyAttribute(child, xsdText, lineStarts, parentPath, schema, issues)
|
|
1286
|
+
);
|
|
1212
1287
|
}
|
|
1213
1288
|
}
|
|
1214
1289
|
return attributes;
|
|
@@ -1245,11 +1320,26 @@ function parseElement(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
|
1245
1320
|
);
|
|
1246
1321
|
}
|
|
1247
1322
|
const qName = node.getAttribute("name");
|
|
1248
|
-
const
|
|
1323
|
+
const namespaceUri4 = getDeclarationNamespaceUri(schema, node, "element");
|
|
1324
|
+
const identityConstraints = children.filter(
|
|
1325
|
+
(child) => ["key", "keyref", "unique"].includes(child.localName)
|
|
1326
|
+
).map(
|
|
1327
|
+
(child) => parseIdentityConstraint(
|
|
1328
|
+
child,
|
|
1329
|
+
xsdText,
|
|
1330
|
+
lineStarts,
|
|
1331
|
+
path,
|
|
1332
|
+
schema,
|
|
1333
|
+
issues,
|
|
1334
|
+
qName ? parseQName(qName).localName : null,
|
|
1335
|
+
namespaceUri4,
|
|
1336
|
+
path
|
|
1337
|
+
)
|
|
1338
|
+
);
|
|
1249
1339
|
return createElementDecl({
|
|
1250
1340
|
name: qName ? parseQName(qName).localName : null,
|
|
1251
1341
|
qName,
|
|
1252
|
-
namespaceUri:
|
|
1342
|
+
namespaceUri: namespaceUri4,
|
|
1253
1343
|
typeName: node.getAttribute("type"),
|
|
1254
1344
|
refName: node.getAttribute("ref"),
|
|
1255
1345
|
inlineType,
|
|
@@ -1258,6 +1348,7 @@ function parseElement(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
|
1258
1348
|
defaultValue: node.getAttribute("default"),
|
|
1259
1349
|
fixedValue: node.getAttribute("fixed"),
|
|
1260
1350
|
nillable: node.getAttribute("nillable") === "true",
|
|
1351
|
+
identityConstraints,
|
|
1261
1352
|
line: loc.line,
|
|
1262
1353
|
column: loc.column,
|
|
1263
1354
|
path
|
|
@@ -1276,20 +1367,101 @@ function parseGroupRef(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
|
1276
1367
|
path
|
|
1277
1368
|
});
|
|
1278
1369
|
}
|
|
1370
|
+
function parseWildcardNamespace(namespaceStr) {
|
|
1371
|
+
if (!namespaceStr) return null;
|
|
1372
|
+
const trimmed = namespaceStr.trim();
|
|
1373
|
+
if (!trimmed) return null;
|
|
1374
|
+
if (trimmed.includes(" ")) {
|
|
1375
|
+
return trimmed.split(/\s+/).filter((ns) => ns);
|
|
1376
|
+
}
|
|
1377
|
+
return trimmed;
|
|
1378
|
+
}
|
|
1379
|
+
function parseNotNamespace(notNamespaceStr) {
|
|
1380
|
+
if (!notNamespaceStr) return [];
|
|
1381
|
+
const trimmed = notNamespaceStr.trim();
|
|
1382
|
+
if (!trimmed) return [];
|
|
1383
|
+
if (trimmed.includes(" ")) {
|
|
1384
|
+
return trimmed.split(/\s+/).filter((ns) => ns);
|
|
1385
|
+
}
|
|
1386
|
+
return [trimmed];
|
|
1387
|
+
}
|
|
1388
|
+
function parseNotQName(notQNameStr) {
|
|
1389
|
+
if (!notQNameStr) return [];
|
|
1390
|
+
const trimmed = notQNameStr.trim();
|
|
1391
|
+
if (!trimmed) return [];
|
|
1392
|
+
if (trimmed.includes(" ")) {
|
|
1393
|
+
return trimmed.split(/\s+/).filter((qn) => qn);
|
|
1394
|
+
}
|
|
1395
|
+
return [trimmed];
|
|
1396
|
+
}
|
|
1279
1397
|
function parseAny(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
1280
1398
|
const path = buildPath(parentPath, node);
|
|
1281
1399
|
const loc = locateNodeInSource(xsdText, lineStarts, node);
|
|
1282
1400
|
collectNodeDiagnostics(schema, issues, node, path, loc);
|
|
1283
1401
|
return createAnyNode({
|
|
1284
|
-
namespace: node.getAttribute("namespace"),
|
|
1402
|
+
namespace: parseWildcardNamespace(node.getAttribute("namespace")),
|
|
1285
1403
|
processContents: node.getAttribute("processContents"),
|
|
1286
1404
|
minOccurs: normalizeOccurs(node.getAttribute("minOccurs"), 1),
|
|
1287
1405
|
maxOccurs: normalizeOccurs(node.getAttribute("maxOccurs"), 1),
|
|
1406
|
+
notNamespace: parseNotNamespace(node.getAttribute("notNamespace")),
|
|
1407
|
+
notQName: parseNotQName(node.getAttribute("notQName")),
|
|
1288
1408
|
line: loc.line,
|
|
1289
1409
|
column: loc.column,
|
|
1290
1410
|
path
|
|
1291
1411
|
});
|
|
1292
1412
|
}
|
|
1413
|
+
function parseAnyAttribute(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
1414
|
+
const path = buildPath(parentPath, node);
|
|
1415
|
+
const loc = locateNodeInSource(xsdText, lineStarts, node);
|
|
1416
|
+
collectNodeDiagnostics(schema, issues, node, path, loc);
|
|
1417
|
+
return createAnyAttributeNode({
|
|
1418
|
+
namespace: parseWildcardNamespace(node.getAttribute("namespace")),
|
|
1419
|
+
processContents: node.getAttribute("processContents"),
|
|
1420
|
+
notNamespace: parseNotNamespace(node.getAttribute("notNamespace")),
|
|
1421
|
+
notQName: parseNotQName(node.getAttribute("notQName")),
|
|
1422
|
+
line: loc.line,
|
|
1423
|
+
column: loc.column,
|
|
1424
|
+
path
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
function parseIdentityConstraint(node, xsdText, lineStarts, parentPath, schema, issues, ownerName, ownerNamespaceUri, ownerPath) {
|
|
1428
|
+
const path = buildPath(parentPath, node);
|
|
1429
|
+
const loc = locateNodeInSource(xsdText, lineStarts, node);
|
|
1430
|
+
collectNodeDiagnostics(schema, issues, node, path, loc);
|
|
1431
|
+
const selectorNode = elementChildren(node).find(
|
|
1432
|
+
(child) => child.localName === "selector"
|
|
1433
|
+
);
|
|
1434
|
+
const selector = selectorNode ? {
|
|
1435
|
+
xpath: selectorNode.getAttribute("xpath"),
|
|
1436
|
+
path: buildPath(path, selectorNode)
|
|
1437
|
+
} : null;
|
|
1438
|
+
const fields = elementChildren(node).filter((child) => child.localName === "field").map((child) => ({
|
|
1439
|
+
xpath: child.getAttribute("xpath"),
|
|
1440
|
+
line: locateNodeInSource(xsdText, lineStarts, child).line,
|
|
1441
|
+
column: locateNodeInSource(xsdText, lineStarts, child).column,
|
|
1442
|
+
path: buildPath(path, child)
|
|
1443
|
+
})).filter((field) => field.xpath != null);
|
|
1444
|
+
const qName = node.getAttribute("name");
|
|
1445
|
+
const name = qName ? parseQName(qName).localName : null;
|
|
1446
|
+
const namespaceUri4 = ownerNamespaceUri || schema.targetNamespace || null;
|
|
1447
|
+
const constraint = createIdentityConstraint({
|
|
1448
|
+
kind: node.localName,
|
|
1449
|
+
name,
|
|
1450
|
+
qName,
|
|
1451
|
+
namespaceUri: namespaceUri4,
|
|
1452
|
+
selector,
|
|
1453
|
+
fields,
|
|
1454
|
+
refer: node.getAttribute("refer"),
|
|
1455
|
+
ownerName,
|
|
1456
|
+
ownerNamespaceUri,
|
|
1457
|
+
ownerPath,
|
|
1458
|
+
line: loc.line,
|
|
1459
|
+
column: loc.column,
|
|
1460
|
+
path
|
|
1461
|
+
});
|
|
1462
|
+
schema.identityConstraints.push(constraint);
|
|
1463
|
+
return constraint;
|
|
1464
|
+
}
|
|
1293
1465
|
function parseContentNode(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
1294
1466
|
const path = buildPath(parentPath, node);
|
|
1295
1467
|
const loc = locateNodeInSource(xsdText, lineStarts, node);
|
|
@@ -1436,6 +1608,22 @@ function parseComplexType(node, xsdText, lineStarts, parentPath, schema, issues)
|
|
|
1436
1608
|
let derivation = { kind: null, baseTypeName: null };
|
|
1437
1609
|
let contentModel = "complex";
|
|
1438
1610
|
const children = elementChildren(node);
|
|
1611
|
+
const namespaceUri4 = schema.targetNamespace || null;
|
|
1612
|
+
const identityConstraints = children.filter(
|
|
1613
|
+
(child) => ["key", "keyref", "unique"].includes(child.localName)
|
|
1614
|
+
).map(
|
|
1615
|
+
(child) => parseIdentityConstraint(
|
|
1616
|
+
child,
|
|
1617
|
+
xsdText,
|
|
1618
|
+
lineStarts,
|
|
1619
|
+
path,
|
|
1620
|
+
schema,
|
|
1621
|
+
issues,
|
|
1622
|
+
null,
|
|
1623
|
+
namespaceUri4,
|
|
1624
|
+
path
|
|
1625
|
+
)
|
|
1626
|
+
);
|
|
1439
1627
|
const directContentNode = children.find(
|
|
1440
1628
|
(child) => ["sequence", "choice", "all", "group", "element", "any"].includes(
|
|
1441
1629
|
child.localName
|
|
@@ -1495,17 +1683,17 @@ function parseComplexType(node, xsdText, lineStarts, parentPath, schema, issues)
|
|
|
1495
1683
|
);
|
|
1496
1684
|
}
|
|
1497
1685
|
const qName = node.getAttribute("name");
|
|
1498
|
-
const namespaceUri3 = schema.targetNamespace || null;
|
|
1499
1686
|
return createComplexTypeDecl({
|
|
1500
1687
|
name: qName ? parseQName(qName).localName : null,
|
|
1501
1688
|
qName,
|
|
1502
|
-
namespaceUri:
|
|
1689
|
+
namespaceUri: namespaceUri4,
|
|
1503
1690
|
content,
|
|
1504
1691
|
attributes,
|
|
1505
1692
|
derivation,
|
|
1506
1693
|
contentModel,
|
|
1507
1694
|
mixed: node.getAttribute("mixed") === "true",
|
|
1508
1695
|
abstract: node.getAttribute("abstract") === "true",
|
|
1696
|
+
identityConstraints,
|
|
1509
1697
|
line: loc.line,
|
|
1510
1698
|
column: loc.column,
|
|
1511
1699
|
path
|
|
@@ -1519,11 +1707,11 @@ function parseGroup(node, xsdText, lineStarts, parentPath, schema, issues) {
|
|
|
1519
1707
|
(child) => ["sequence", "choice", "all"].includes(child.localName)
|
|
1520
1708
|
);
|
|
1521
1709
|
const qName = node.getAttribute("name");
|
|
1522
|
-
const
|
|
1710
|
+
const namespaceUri4 = schema.targetNamespace || null;
|
|
1523
1711
|
return createGroupDecl({
|
|
1524
1712
|
name: qName ? parseQName(qName).localName : null,
|
|
1525
1713
|
qName,
|
|
1526
|
-
namespaceUri:
|
|
1714
|
+
namespaceUri: namespaceUri4,
|
|
1527
1715
|
content: contentNode ? parseContentNode(contentNode, xsdText, lineStarts, path, schema, issues) : null,
|
|
1528
1716
|
line: loc.line,
|
|
1529
1717
|
column: loc.column,
|
|
@@ -1545,11 +1733,11 @@ function parseAttributeGroup(node, xsdText, lineStarts, parentPath, schema, issu
|
|
|
1545
1733
|
issues
|
|
1546
1734
|
);
|
|
1547
1735
|
const qName = node.getAttribute("name");
|
|
1548
|
-
const
|
|
1736
|
+
const namespaceUri4 = schema.targetNamespace || null;
|
|
1549
1737
|
return createAttributeGroupDecl({
|
|
1550
1738
|
name: qName ? parseQName(qName).localName : null,
|
|
1551
1739
|
qName,
|
|
1552
|
-
namespaceUri:
|
|
1740
|
+
namespaceUri: namespaceUri4,
|
|
1553
1741
|
attributes,
|
|
1554
1742
|
line: loc.line,
|
|
1555
1743
|
column: loc.column,
|
|
@@ -1653,24 +1841,24 @@ function resolveExternalDocument(ref, externalDocuments) {
|
|
|
1653
1841
|
}
|
|
1654
1842
|
}
|
|
1655
1843
|
if (ref?.kind === "import" && ref.namespace) {
|
|
1656
|
-
const
|
|
1844
|
+
const namespaceMatches2 = entries.filter((entry) => {
|
|
1657
1845
|
const declaredTargetNamespace = getDeclaredTargetNamespaceFromText(
|
|
1658
1846
|
entry.text
|
|
1659
1847
|
);
|
|
1660
1848
|
return (declaredTargetNamespace || null) === (ref.namespace || null);
|
|
1661
1849
|
});
|
|
1662
|
-
if (
|
|
1850
|
+
if (namespaceMatches2.length === 1) {
|
|
1663
1851
|
return {
|
|
1664
1852
|
kind: "namespace",
|
|
1665
|
-
entry:
|
|
1666
|
-
matches:
|
|
1853
|
+
entry: namespaceMatches2[0],
|
|
1854
|
+
matches: namespaceMatches2
|
|
1667
1855
|
};
|
|
1668
1856
|
}
|
|
1669
|
-
if (
|
|
1857
|
+
if (namespaceMatches2.length > 1) {
|
|
1670
1858
|
return {
|
|
1671
1859
|
kind: "ambiguous-namespace",
|
|
1672
1860
|
entry: null,
|
|
1673
|
-
matches:
|
|
1861
|
+
matches: namespaceMatches2
|
|
1674
1862
|
};
|
|
1675
1863
|
}
|
|
1676
1864
|
}
|
|
@@ -2287,6 +2475,115 @@ function checkRestrictedAttributes(schema, derivedType, baseType, issues) {
|
|
|
2287
2475
|
}
|
|
2288
2476
|
}
|
|
2289
2477
|
}
|
|
2478
|
+
function checkWildcardRestriction(schema, derivedType, baseType, issues) {
|
|
2479
|
+
const derivedContent = getEffectiveContent(schema, derivedType);
|
|
2480
|
+
const baseContent = getEffectiveContent(schema, baseType);
|
|
2481
|
+
const derivedWildcards = [];
|
|
2482
|
+
const baseWildcards = [];
|
|
2483
|
+
function collectWildcards(node, arr) {
|
|
2484
|
+
if (!node) return;
|
|
2485
|
+
if (node.kind === "any") {
|
|
2486
|
+
arr.push(node);
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
if (node.children) {
|
|
2490
|
+
for (const child of asArray(node.children)) {
|
|
2491
|
+
collectWildcards(child, arr);
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
collectWildcards(derivedContent, derivedWildcards);
|
|
2496
|
+
collectWildcards(baseContent, baseWildcards);
|
|
2497
|
+
if (derivedWildcards.length > 0 && baseWildcards.length === 0) {
|
|
2498
|
+
issues.push(
|
|
2499
|
+
buildRestrictionIssue(
|
|
2500
|
+
"XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
|
|
2501
|
+
`Restricted type introduces wildcard elements that base type does not have.`,
|
|
2502
|
+
derivedType
|
|
2503
|
+
)
|
|
2504
|
+
);
|
|
2505
|
+
}
|
|
2506
|
+
const derivedAttrs = asArray(getEffectiveAttributes(schema, derivedType));
|
|
2507
|
+
const baseAttrs = asArray(getEffectiveAttributes(schema, baseType));
|
|
2508
|
+
const derivedHasAnyAttribute = derivedAttrs.some((a) => a?.kind === "anyAttribute");
|
|
2509
|
+
const baseHasAnyAttribute = baseAttrs.some((a) => a?.kind === "anyAttribute");
|
|
2510
|
+
if (derivedHasAnyAttribute && !baseHasAnyAttribute) {
|
|
2511
|
+
issues.push(
|
|
2512
|
+
buildRestrictionIssue(
|
|
2513
|
+
"XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
|
|
2514
|
+
`Restricted type introduces anyAttribute that base type does not have.`,
|
|
2515
|
+
derivedType
|
|
2516
|
+
)
|
|
2517
|
+
);
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
function checkOccurrenceCompatibility(derived, base, name) {
|
|
2521
|
+
const dMin = typeof derived.minOccurs === "number" ? derived.minOccurs : 1;
|
|
2522
|
+
const bMin = typeof base.minOccurs === "number" ? base.minOccurs : 1;
|
|
2523
|
+
const dMax = maxToNumber(derived.maxOccurs ?? 1);
|
|
2524
|
+
const bMax = maxToNumber(base.maxOccurs ?? 1);
|
|
2525
|
+
return dMin >= bMin && dMax <= bMax;
|
|
2526
|
+
}
|
|
2527
|
+
function checkComplexContentRestriction(schema, derivedType, baseType, issues) {
|
|
2528
|
+
const derivedContent = getEffectiveContent(schema, derivedType);
|
|
2529
|
+
const baseContent = getEffectiveContent(schema, baseType);
|
|
2530
|
+
if (!derivedContent || !baseContent) return;
|
|
2531
|
+
const derivedFlat = flattenContent(derivedContent, []);
|
|
2532
|
+
const baseFlat = flattenContent(baseContent, []);
|
|
2533
|
+
const baseMap = new Map(baseFlat.map((item) => [item.name, item]));
|
|
2534
|
+
for (const item of derivedFlat) {
|
|
2535
|
+
const baseItem = baseMap.get(item.name);
|
|
2536
|
+
if (!baseItem) {
|
|
2537
|
+
issues.push(
|
|
2538
|
+
buildRestrictionIssue(
|
|
2539
|
+
"XSD_RESTRICTION_NOT_SUBSET",
|
|
2540
|
+
`Restricted type contains element '${item.name}' not in base type.`,
|
|
2541
|
+
item
|
|
2542
|
+
)
|
|
2543
|
+
);
|
|
2544
|
+
continue;
|
|
2545
|
+
}
|
|
2546
|
+
if (!checkOccurrenceCompatibility(item, baseItem, item.name)) {
|
|
2547
|
+
issues.push(
|
|
2548
|
+
buildRestrictionIssue(
|
|
2549
|
+
"XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE",
|
|
2550
|
+
`Restricted type has incompatible occurrence constraints for '${item.name}'.`,
|
|
2551
|
+
item
|
|
2552
|
+
)
|
|
2553
|
+
);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
function checkSimpleContentRestriction(schema, derivedType, baseType, issues) {
|
|
2558
|
+
if (baseType.contentModel !== "simple") {
|
|
2559
|
+
issues.push(
|
|
2560
|
+
buildRestrictionIssue(
|
|
2561
|
+
"XSD_RESTRICTION_NOT_SUBSET",
|
|
2562
|
+
`SimpleContent restriction requires base type to have simple content.`,
|
|
2563
|
+
derivedType
|
|
2564
|
+
)
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
const derivedAttrs = asArray(getEffectiveAttributes(schema, derivedType));
|
|
2568
|
+
const baseAttrs = asArray(getEffectiveAttributes(schema, baseType));
|
|
2569
|
+
const baseAttrMap = new Map(
|
|
2570
|
+
baseAttrs.filter((attr) => attr?.kind === "attribute").map((attr) => [localDeclName(attr), attr])
|
|
2571
|
+
);
|
|
2572
|
+
for (const attr of derivedAttrs) {
|
|
2573
|
+
if (attr?.kind !== "attribute") continue;
|
|
2574
|
+
const name = localDeclName(attr);
|
|
2575
|
+
const baseAttr = baseAttrMap.get(name);
|
|
2576
|
+
if (!baseAttr && !baseAttrs.some((a) => a?.kind === "anyAttribute")) {
|
|
2577
|
+
issues.push(
|
|
2578
|
+
buildRestrictionIssue(
|
|
2579
|
+
"XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE",
|
|
2580
|
+
`SimpleContent restricted type adds attribute '${name}' not in base type.`,
|
|
2581
|
+
attr
|
|
2582
|
+
)
|
|
2583
|
+
);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2290
2587
|
function runRestrictionDiagnostics(schema) {
|
|
2291
2588
|
const issues = [];
|
|
2292
2589
|
for (const complexType of Object.values(schema.globals.complexTypes || {})) {
|
|
@@ -2296,6 +2593,12 @@ function runRestrictionDiagnostics(schema) {
|
|
|
2296
2593
|
if (!baseType) continue;
|
|
2297
2594
|
checkRestrictedContentSubset(schema, complexType, baseType, issues);
|
|
2298
2595
|
checkRestrictedAttributes(schema, complexType, baseType, issues);
|
|
2596
|
+
checkWildcardRestriction(schema, complexType, baseType, issues);
|
|
2597
|
+
if (complexType.contentModel === "complex" && baseType.contentModel === "complex") {
|
|
2598
|
+
checkComplexContentRestriction(schema, complexType, baseType, issues);
|
|
2599
|
+
} else if (complexType.contentModel === "simple" && baseType.contentModel === "simple") {
|
|
2600
|
+
checkSimpleContentRestriction(schema, complexType, baseType, issues);
|
|
2601
|
+
}
|
|
2299
2602
|
}
|
|
2300
2603
|
return issues;
|
|
2301
2604
|
}
|
|
@@ -2332,6 +2635,188 @@ function runDefaultFixedDiagnostics(schema) {
|
|
|
2332
2635
|
return issues;
|
|
2333
2636
|
}
|
|
2334
2637
|
|
|
2638
|
+
// src/diagnostics/schemaIdentityConstraintDiagnostics.js
|
|
2639
|
+
function isValidConstraintXPath(xpath) {
|
|
2640
|
+
if (!xpath || typeof xpath !== "string") return false;
|
|
2641
|
+
const trimmed = xpath.trim();
|
|
2642
|
+
if (!trimmed) return false;
|
|
2643
|
+
let normalized = trimmed;
|
|
2644
|
+
if (trimmed.startsWith("./")) {
|
|
2645
|
+
if (trimmed.startsWith(".//")) normalized = trimmed.slice(1);
|
|
2646
|
+
else normalized = trimmed.slice(2);
|
|
2647
|
+
}
|
|
2648
|
+
if (normalized.startsWith("/") && !normalized.startsWith("//")) return false;
|
|
2649
|
+
if (normalized.includes("///")) return false;
|
|
2650
|
+
let segments = normalized.split(
|
|
2651
|
+
/\/+/
|
|
2652
|
+
);
|
|
2653
|
+
if (normalized.startsWith("//")) segments = segments.slice(1);
|
|
2654
|
+
if (normalized.endsWith("//")) segments = segments.slice(0, -1);
|
|
2655
|
+
if (segments.some((segment) => segment.length === 0)) return false;
|
|
2656
|
+
for (const segment of segments) {
|
|
2657
|
+
if (segment === ".") continue;
|
|
2658
|
+
if (segment === "*") continue;
|
|
2659
|
+
if (segment.startsWith("@")) {
|
|
2660
|
+
const attrName = segment.slice(1);
|
|
2661
|
+
if (!/^[A-Za-z_][\w.-]*$/.test(attrName)) return false;
|
|
2662
|
+
continue;
|
|
2663
|
+
}
|
|
2664
|
+
const parsed = parseQName(segment);
|
|
2665
|
+
if (!parsed.localName) return false;
|
|
2666
|
+
}
|
|
2667
|
+
return true;
|
|
2668
|
+
}
|
|
2669
|
+
function getConstraintKey(constraint) {
|
|
2670
|
+
return `${constraint.ownerPath || ""}::${constraint.name || ""}`;
|
|
2671
|
+
}
|
|
2672
|
+
function findReferencedKey(schema, refer) {
|
|
2673
|
+
if (!refer) return null;
|
|
2674
|
+
const referName = parseQName(refer).localName;
|
|
2675
|
+
return schema.identityConstraints.find(
|
|
2676
|
+
(constraint) => constraint.kind === "key" && constraint.name === referName
|
|
2677
|
+
);
|
|
2678
|
+
}
|
|
2679
|
+
function runIdentityConstraintDiagnostics(schema) {
|
|
2680
|
+
const issues = [];
|
|
2681
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
2682
|
+
for (const constraint of schema.identityConstraints || []) {
|
|
2683
|
+
const key = getConstraintKey(constraint);
|
|
2684
|
+
if (seenNames.has(key)) {
|
|
2685
|
+
issues.push(
|
|
2686
|
+
createIssue({
|
|
2687
|
+
code: ISSUE_CODES.DUPLICATE_CONSTRAINT_NAME,
|
|
2688
|
+
severity: "error",
|
|
2689
|
+
message: `Duplicate identity constraint name '${constraint.name}' in the same scope.`,
|
|
2690
|
+
line: constraint.line,
|
|
2691
|
+
column: constraint.column,
|
|
2692
|
+
path: constraint.path,
|
|
2693
|
+
source: "xsd",
|
|
2694
|
+
nodeKind: constraint.kind,
|
|
2695
|
+
name: constraint.name,
|
|
2696
|
+
details: {
|
|
2697
|
+
ownerPath: constraint.ownerPath,
|
|
2698
|
+
ownerName: constraint.ownerName
|
|
2699
|
+
}
|
|
2700
|
+
})
|
|
2701
|
+
);
|
|
2702
|
+
} else {
|
|
2703
|
+
seenNames.add(key);
|
|
2704
|
+
}
|
|
2705
|
+
if (!constraint.selector || !constraint.selector.xpath) {
|
|
2706
|
+
issues.push(
|
|
2707
|
+
createIssue({
|
|
2708
|
+
code: ISSUE_CODES.INVALID_CONSTRAINT_SELECTOR,
|
|
2709
|
+
severity: "error",
|
|
2710
|
+
message: `Identity constraint '${constraint.name || constraint.kind}' is missing a selector xpath.`,
|
|
2711
|
+
line: constraint.line,
|
|
2712
|
+
column: constraint.column,
|
|
2713
|
+
path: constraint.path,
|
|
2714
|
+
source: "xsd",
|
|
2715
|
+
nodeKind: constraint.kind,
|
|
2716
|
+
name: constraint.name,
|
|
2717
|
+
details: {
|
|
2718
|
+
ownerPath: constraint.ownerPath,
|
|
2719
|
+
ownerName: constraint.ownerName
|
|
2720
|
+
}
|
|
2721
|
+
})
|
|
2722
|
+
);
|
|
2723
|
+
} else if (!isValidConstraintXPath(constraint.selector.xpath)) {
|
|
2724
|
+
issues.push(
|
|
2725
|
+
createIssue({
|
|
2726
|
+
code: ISSUE_CODES.INVALID_CONSTRAINT_SELECTOR,
|
|
2727
|
+
severity: "error",
|
|
2728
|
+
message: `Invalid selector xpath '${constraint.selector.xpath}'.`,
|
|
2729
|
+
line: constraint.line,
|
|
2730
|
+
column: constraint.column,
|
|
2731
|
+
path: constraint.selector.path,
|
|
2732
|
+
source: "xsd",
|
|
2733
|
+
nodeKind: constraint.kind,
|
|
2734
|
+
name: constraint.name,
|
|
2735
|
+
details: {
|
|
2736
|
+
selector: constraint.selector.xpath,
|
|
2737
|
+
ownerPath: constraint.ownerPath
|
|
2738
|
+
}
|
|
2739
|
+
})
|
|
2740
|
+
);
|
|
2741
|
+
}
|
|
2742
|
+
if (!constraint.fields?.length) {
|
|
2743
|
+
issues.push(
|
|
2744
|
+
createIssue({
|
|
2745
|
+
code: ISSUE_CODES.INVALID_CONSTRAINT_FIELD,
|
|
2746
|
+
severity: "error",
|
|
2747
|
+
message: `Identity constraint '${constraint.name || constraint.kind}' must declare at least one field.`,
|
|
2748
|
+
line: constraint.line,
|
|
2749
|
+
column: constraint.column,
|
|
2750
|
+
path: constraint.path,
|
|
2751
|
+
source: "xsd",
|
|
2752
|
+
nodeKind: constraint.kind,
|
|
2753
|
+
name: constraint.name,
|
|
2754
|
+
details: { ownerPath: constraint.ownerPath }
|
|
2755
|
+
})
|
|
2756
|
+
);
|
|
2757
|
+
} else {
|
|
2758
|
+
for (const field of constraint.fields) {
|
|
2759
|
+
if (!field.xpath || !isValidConstraintXPath(field.xpath)) {
|
|
2760
|
+
issues.push(
|
|
2761
|
+
createIssue({
|
|
2762
|
+
code: ISSUE_CODES.INVALID_CONSTRAINT_FIELD,
|
|
2763
|
+
severity: "error",
|
|
2764
|
+
message: `Invalid field xpath '${field.xpath}'.`,
|
|
2765
|
+
line: field.line,
|
|
2766
|
+
column: field.column,
|
|
2767
|
+
path: field.path,
|
|
2768
|
+
source: "xsd",
|
|
2769
|
+
nodeKind: constraint.kind,
|
|
2770
|
+
name: constraint.name,
|
|
2771
|
+
details: {
|
|
2772
|
+
field: field.xpath,
|
|
2773
|
+
ownerPath: constraint.ownerPath
|
|
2774
|
+
}
|
|
2775
|
+
})
|
|
2776
|
+
);
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
if (constraint.kind === "keyref") {
|
|
2781
|
+
if (!constraint.refer) {
|
|
2782
|
+
issues.push(
|
|
2783
|
+
createIssue({
|
|
2784
|
+
code: ISSUE_CODES.UNKNOWN_KEY_REFERENCE,
|
|
2785
|
+
severity: "error",
|
|
2786
|
+
message: `xs:keyref '${constraint.name || "unnamed"}' is missing a refer attribute.`,
|
|
2787
|
+
line: constraint.line,
|
|
2788
|
+
column: constraint.column,
|
|
2789
|
+
path: constraint.path,
|
|
2790
|
+
source: "xsd",
|
|
2791
|
+
nodeKind: constraint.kind,
|
|
2792
|
+
name: constraint.name,
|
|
2793
|
+
details: { ownerPath: constraint.ownerPath }
|
|
2794
|
+
})
|
|
2795
|
+
);
|
|
2796
|
+
} else if (!findReferencedKey(schema, constraint.refer)) {
|
|
2797
|
+
issues.push(
|
|
2798
|
+
createIssue({
|
|
2799
|
+
code: ISSUE_CODES.UNKNOWN_KEY_REFERENCE,
|
|
2800
|
+
severity: "error",
|
|
2801
|
+
message: `xs:keyref refers to unknown key '${constraint.refer}'.`,
|
|
2802
|
+
line: constraint.line,
|
|
2803
|
+
column: constraint.column,
|
|
2804
|
+
path: constraint.path,
|
|
2805
|
+
source: "xsd",
|
|
2806
|
+
nodeKind: constraint.kind,
|
|
2807
|
+
name: constraint.name,
|
|
2808
|
+
details: {
|
|
2809
|
+
refer: constraint.refer,
|
|
2810
|
+
ownerPath: constraint.ownerPath
|
|
2811
|
+
}
|
|
2812
|
+
})
|
|
2813
|
+
);
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
return issues;
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2335
2820
|
// src/diagnostics/schemaImportDiagnostics.js
|
|
2336
2821
|
function normalizeSchemaPath2(value) {
|
|
2337
2822
|
if (!value || typeof value !== "string") return null;
|
|
@@ -2440,6 +2925,130 @@ function runImportDiagnostics(schema, options = {}) {
|
|
|
2440
2925
|
return issues;
|
|
2441
2926
|
}
|
|
2442
2927
|
|
|
2928
|
+
// src/diagnostics/schemaWildcardDiagnostics.js
|
|
2929
|
+
function validateWildcardNamespace(namespace, path) {
|
|
2930
|
+
if (!namespace) return null;
|
|
2931
|
+
const trimmed = namespace.trim();
|
|
2932
|
+
if (!trimmed) return null;
|
|
2933
|
+
const parts = trimmed.split(/\s+/);
|
|
2934
|
+
for (const part of parts) {
|
|
2935
|
+
if (part === "##any" || part === "##other" || part === "##targetNamespace") {
|
|
2936
|
+
continue;
|
|
2937
|
+
}
|
|
2938
|
+
if (!part.includes(":") && part !== "") {
|
|
2939
|
+
return createIssue({
|
|
2940
|
+
code: "INVALID_WILDCARD_NAMESPACE",
|
|
2941
|
+
severity: "warning",
|
|
2942
|
+
message: `Invalid namespace in wildcard constraint: '${part}'. Expected ##any, ##other, ##targetNamespace, or a valid namespace URI.`,
|
|
2943
|
+
path
|
|
2944
|
+
});
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
return null;
|
|
2948
|
+
}
|
|
2949
|
+
function validateProcessContents(processContents, path) {
|
|
2950
|
+
if (!processContents) return null;
|
|
2951
|
+
const trimmed = processContents.trim();
|
|
2952
|
+
if (trimmed === "strict" || trimmed === "lax" || trimmed === "skip") {
|
|
2953
|
+
return null;
|
|
2954
|
+
}
|
|
2955
|
+
return createIssue({
|
|
2956
|
+
code: "INVALID_PROCESS_CONTENTS",
|
|
2957
|
+
severity: "error",
|
|
2958
|
+
message: `Invalid processContents value: '${processContents}'. Must be 'strict', 'lax', or 'skip'.`,
|
|
2959
|
+
path
|
|
2960
|
+
});
|
|
2961
|
+
}
|
|
2962
|
+
function validateSingleWildcard(wildcardNode, nodeName) {
|
|
2963
|
+
const issues = [];
|
|
2964
|
+
const nsIssue = validateWildcardNamespace(wildcardNode.namespace, wildcardNode.path);
|
|
2965
|
+
if (nsIssue) {
|
|
2966
|
+
issues.push(nsIssue);
|
|
2967
|
+
}
|
|
2968
|
+
const pcIssue = validateProcessContents(wildcardNode.processContents, wildcardNode.path);
|
|
2969
|
+
if (pcIssue) {
|
|
2970
|
+
issues.push(pcIssue);
|
|
2971
|
+
}
|
|
2972
|
+
if (wildcardNode.notNamespace && wildcardNode.notNamespace.length > 0) {
|
|
2973
|
+
if (wildcardNode.namespace !== "##other" && wildcardNode.namespace !== "##targetNamespace") {
|
|
2974
|
+
issues.push(
|
|
2975
|
+
createIssue({
|
|
2976
|
+
code: "INVALID_NOT_NAMESPACE_USAGE",
|
|
2977
|
+
severity: "warning",
|
|
2978
|
+
message: `notNamespace is only meaningful with ##other or ##targetNamespace namespace constraint.`,
|
|
2979
|
+
path: wildcardNode.path
|
|
2980
|
+
})
|
|
2981
|
+
);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
if (wildcardNode.notQName && wildcardNode.notQName.length > 0) {
|
|
2985
|
+
for (const qname of wildcardNode.notQName) {
|
|
2986
|
+
if (!qname || qname.trim() === "") {
|
|
2987
|
+
issues.push(
|
|
2988
|
+
createIssue({
|
|
2989
|
+
code: "INVALID_NOT_QNAME",
|
|
2990
|
+
severity: "warning",
|
|
2991
|
+
message: `Empty QName in notQName constraint.`,
|
|
2992
|
+
path: wildcardNode.path
|
|
2993
|
+
})
|
|
2994
|
+
);
|
|
2995
|
+
break;
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
return issues;
|
|
3000
|
+
}
|
|
3001
|
+
function findWildcardsInContent(node, wildcards) {
|
|
3002
|
+
if (!node) return;
|
|
3003
|
+
if (node.kind === "any" || node.kind === "anyAttribute") {
|
|
3004
|
+
wildcards.push(node);
|
|
3005
|
+
return;
|
|
3006
|
+
}
|
|
3007
|
+
if (node.children && Array.isArray(node.children)) {
|
|
3008
|
+
for (const child of node.children) {
|
|
3009
|
+
findWildcardsInContent(child, wildcards);
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
function findWildcardsInAttributes(attributes, wildcards) {
|
|
3014
|
+
if (!attributes || !Array.isArray(attributes)) return;
|
|
3015
|
+
for (const attr of attributes) {
|
|
3016
|
+
if (attr.kind === "anyAttribute") {
|
|
3017
|
+
wildcards.push(attr);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
function runWildcardDiagnostics(schema) {
|
|
3022
|
+
const issues = [];
|
|
3023
|
+
const wildcards = [];
|
|
3024
|
+
for (const elem of Object.values(schema.globals.elements || {})) {
|
|
3025
|
+
if (elem.inlineType?.content) {
|
|
3026
|
+
findWildcardsInContent(elem.inlineType.content, wildcards);
|
|
3027
|
+
}
|
|
3028
|
+
if (elem.inlineType?.attributes) {
|
|
3029
|
+
findWildcardsInAttributes(elem.inlineType.attributes, wildcards);
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
for (const complexType of Object.values(schema.globals.complexTypes || {})) {
|
|
3033
|
+
if (complexType.content) {
|
|
3034
|
+
findWildcardsInContent(complexType.content, wildcards);
|
|
3035
|
+
}
|
|
3036
|
+
if (complexType.attributes) {
|
|
3037
|
+
findWildcardsInAttributes(complexType.attributes, wildcards);
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
for (const group of Object.values(schema.globals.groups || {})) {
|
|
3041
|
+
if (group.content) {
|
|
3042
|
+
findWildcardsInContent(group.content, wildcards);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
for (const wildcard of wildcards) {
|
|
3046
|
+
const wildcardIssues = validateSingleWildcard(wildcard, wildcard.kind);
|
|
3047
|
+
issues.push(...wildcardIssues);
|
|
3048
|
+
}
|
|
3049
|
+
return issues;
|
|
3050
|
+
}
|
|
3051
|
+
|
|
2443
3052
|
// src/diagnostics/schemaDiagnostics.js
|
|
2444
3053
|
function buildStats(schema) {
|
|
2445
3054
|
return {
|
|
@@ -2467,11 +3076,14 @@ function getSupportedFeatures(schema) {
|
|
|
2467
3076
|
"element",
|
|
2468
3077
|
"extension",
|
|
2469
3078
|
"group",
|
|
3079
|
+
"key",
|
|
3080
|
+
"keyref",
|
|
2470
3081
|
"restriction",
|
|
2471
3082
|
"schema",
|
|
2472
3083
|
"sequence",
|
|
2473
3084
|
"simpleContent",
|
|
2474
|
-
"simpleType"
|
|
3085
|
+
"simpleType",
|
|
3086
|
+
"unique"
|
|
2475
3087
|
].includes(name)
|
|
2476
3088
|
).map((name) => `xs:${name}`)
|
|
2477
3089
|
);
|
|
@@ -2608,7 +3220,11 @@ function runSchemaDiagnostics(schema, options = {}) {
|
|
|
2608
3220
|
checkMissingBaseTypes(schema, issues);
|
|
2609
3221
|
checkUnknownGroups(schema, issues);
|
|
2610
3222
|
checkUnknownAttributeGroups(schema, issues);
|
|
3223
|
+
const identityIssues = runIdentityConstraintDiagnostics(schema);
|
|
3224
|
+
issues.push(...identityIssues);
|
|
2611
3225
|
emitUnsupportedFeatureWarnings(schema, issues, options);
|
|
3226
|
+
const wildcardIssues = runWildcardDiagnostics(schema);
|
|
3227
|
+
issues.push(...wildcardIssues);
|
|
2612
3228
|
const facetIssues = runFacetDiagnostics(schema, options);
|
|
2613
3229
|
issues.push(...facetIssues);
|
|
2614
3230
|
const restrictionIssues = runRestrictionDiagnostics(schema);
|
|
@@ -2629,7 +3245,7 @@ function runSchemaDiagnostics(schema, options = {}) {
|
|
|
2629
3245
|
}
|
|
2630
3246
|
|
|
2631
3247
|
// src/version.js
|
|
2632
|
-
var ENGINE_VERSION = "v0.
|
|
3248
|
+
var ENGINE_VERSION = "v0.2.1";
|
|
2633
3249
|
|
|
2634
3250
|
// src/utils/result.js
|
|
2635
3251
|
function summarizeIssues(issues = []) {
|
|
@@ -2695,7 +3311,7 @@ function createTreeNode({
|
|
|
2695
3311
|
refName = null,
|
|
2696
3312
|
baseTypeName = null,
|
|
2697
3313
|
derivation = null,
|
|
2698
|
-
namespaceUri:
|
|
3314
|
+
namespaceUri: namespaceUri4 = null,
|
|
2699
3315
|
minOccurs = 1,
|
|
2700
3316
|
maxOccurs = 1,
|
|
2701
3317
|
use = null,
|
|
@@ -2712,7 +3328,7 @@ function createTreeNode({
|
|
|
2712
3328
|
refName,
|
|
2713
3329
|
baseTypeName,
|
|
2714
3330
|
derivation,
|
|
2715
|
-
namespaceUri:
|
|
3331
|
+
namespaceUri: namespaceUri4,
|
|
2716
3332
|
minOccurs,
|
|
2717
3333
|
maxOccurs,
|
|
2718
3334
|
use,
|
|
@@ -2724,9 +3340,9 @@ function createTreeNode({
|
|
|
2724
3340
|
}
|
|
2725
3341
|
|
|
2726
3342
|
// src/tree/extractTree.js
|
|
2727
|
-
function buildQualifiedLabel(name,
|
|
3343
|
+
function buildQualifiedLabel(name, namespaceUri4) {
|
|
2728
3344
|
if (!name) return name;
|
|
2729
|
-
return
|
|
3345
|
+
return namespaceUri4 ? `{${namespaceUri4}} ${name}` : name;
|
|
2730
3346
|
}
|
|
2731
3347
|
function asArray2(value) {
|
|
2732
3348
|
return Array.isArray(value) ? value : [];
|
|
@@ -3367,8 +3983,8 @@ function mergeAttributes(target, source) {
|
|
|
3367
3983
|
Object.assign(target, source);
|
|
3368
3984
|
}
|
|
3369
3985
|
function qualifiedElementName(schema, elementDecl, state, isRoot = false) {
|
|
3370
|
-
const
|
|
3371
|
-
const bare =
|
|
3986
|
+
const localName4 = elementDecl.name || elementDecl.refName || "element";
|
|
3987
|
+
const bare = localName4.includes(":") ? localName4.split(":")[1] : localName4;
|
|
3372
3988
|
const ns = elementDecl.namespaceUri;
|
|
3373
3989
|
if (!ns) return bare;
|
|
3374
3990
|
const prefix = state.nsContext.getPrefix(ns);
|
|
@@ -3517,6 +4133,24 @@ function buildNodesFromContent(schema, contentNode, options, state) {
|
|
|
3517
4133
|
function buildComplexTypeContent(schema, complexTypeDecl, options, state) {
|
|
3518
4134
|
const content = getEffectiveContent(schema, complexTypeDecl);
|
|
3519
4135
|
const attributes = getEffectiveAttributes(schema, complexTypeDecl);
|
|
4136
|
+
if (state.currentDepth >= options.maxDepth) {
|
|
4137
|
+
return {
|
|
4138
|
+
attributes: buildAttributesObject(schema, attributes, options, state),
|
|
4139
|
+
children: []
|
|
4140
|
+
};
|
|
4141
|
+
}
|
|
4142
|
+
const typeKey = complexTypeDecl.name || complexTypeDecl.qName;
|
|
4143
|
+
if (typeKey && state.visitedTypes.has(typeKey)) {
|
|
4144
|
+
return {
|
|
4145
|
+
attributes: buildAttributesObject(schema, attributes, options, state),
|
|
4146
|
+
children: []
|
|
4147
|
+
};
|
|
4148
|
+
}
|
|
4149
|
+
if (typeKey) {
|
|
4150
|
+
state.visitedTypes.add(typeKey);
|
|
4151
|
+
}
|
|
4152
|
+
const previousDepth = state.currentDepth;
|
|
4153
|
+
state.currentDepth += 1;
|
|
3520
4154
|
let children = content ? buildNodesFromContent(schema, content, options, state) : [];
|
|
3521
4155
|
if (options.mode === "minimal" && children.length === 0 && content) {
|
|
3522
4156
|
children = buildRepresentativeNodesFromContent(
|
|
@@ -3526,6 +4160,10 @@ function buildComplexTypeContent(schema, complexTypeDecl, options, state) {
|
|
|
3526
4160
|
state
|
|
3527
4161
|
);
|
|
3528
4162
|
}
|
|
4163
|
+
state.currentDepth = previousDepth;
|
|
4164
|
+
if (typeKey) {
|
|
4165
|
+
state.visitedTypes.delete(typeKey);
|
|
4166
|
+
}
|
|
3529
4167
|
return {
|
|
3530
4168
|
attributes: buildAttributesObject(schema, attributes, options, state),
|
|
3531
4169
|
children
|
|
@@ -3604,7 +4242,10 @@ function selectRoot(schema, options = {}) {
|
|
|
3604
4242
|
function generateXmlFromSchema(schema, options = {}, helpers = {}) {
|
|
3605
4243
|
const normalizedOptions = {
|
|
3606
4244
|
mode: options.mode === "full" ? "full" : "minimal",
|
|
3607
|
-
includeOptionalAttributes: options.includeOptionalAttributes === true
|
|
4245
|
+
includeOptionalAttributes: options.includeOptionalAttributes === true,
|
|
4246
|
+
maxDepth: options.maxDepth ?? 3,
|
|
4247
|
+
maxChoiceBranches: options.maxChoiceBranches ?? 1,
|
|
4248
|
+
expandRepeatingElements: options.expandRepeatingElements ?? 2
|
|
3608
4249
|
};
|
|
3609
4250
|
const root = selectRoot(schema, options);
|
|
3610
4251
|
if (!root) {
|
|
@@ -3617,7 +4258,9 @@ function generateXmlFromSchema(schema, options = {}, helpers = {}) {
|
|
|
3617
4258
|
const state = {
|
|
3618
4259
|
resolveAttributeGroup: helpers.resolveAttributeGroup,
|
|
3619
4260
|
targetPrefix: options.targetPrefix || "tns",
|
|
3620
|
-
nsContext
|
|
4261
|
+
nsContext,
|
|
4262
|
+
visitedTypes: /* @__PURE__ */ new Set(),
|
|
4263
|
+
currentDepth: 0
|
|
3621
4264
|
};
|
|
3622
4265
|
const [rootNode] = buildElementInstances(
|
|
3623
4266
|
schema,
|
|
@@ -3720,6 +4363,80 @@ function generateSampleXml({ xsdText, options = {} } = {}) {
|
|
|
3720
4363
|
});
|
|
3721
4364
|
}
|
|
3722
4365
|
|
|
4366
|
+
// src/validation/wildcardValidator.js
|
|
4367
|
+
function namespaceMatches(elementNamespace, wildcardNamespace, targetNamespace) {
|
|
4368
|
+
if (!wildcardNamespace) return true;
|
|
4369
|
+
if (wildcardNamespace === "##any") return true;
|
|
4370
|
+
if (wildcardNamespace === "##targetNamespace") {
|
|
4371
|
+
return elementNamespace === targetNamespace;
|
|
4372
|
+
}
|
|
4373
|
+
if (wildcardNamespace === "##other") {
|
|
4374
|
+
return elementNamespace !== targetNamespace;
|
|
4375
|
+
}
|
|
4376
|
+
if (Array.isArray(wildcardNamespace)) {
|
|
4377
|
+
return wildcardNamespace.includes(elementNamespace);
|
|
4378
|
+
}
|
|
4379
|
+
return elementNamespace === wildcardNamespace;
|
|
4380
|
+
}
|
|
4381
|
+
function isExcludedByNotNamespace(elementNamespace, notNamespace) {
|
|
4382
|
+
if (!notNamespace || notNamespace.length === 0) return false;
|
|
4383
|
+
return notNamespace.includes(elementNamespace);
|
|
4384
|
+
}
|
|
4385
|
+
function isExcludedByNotQName(qName, notQName) {
|
|
4386
|
+
if (!notQName || notQName.length === 0) return false;
|
|
4387
|
+
return notQName.includes(qName);
|
|
4388
|
+
}
|
|
4389
|
+
function buildQName(localName4, namespaceUri4) {
|
|
4390
|
+
if (!namespaceUri4 || namespaceUri4 === "") {
|
|
4391
|
+
return localName4;
|
|
4392
|
+
}
|
|
4393
|
+
return `{${namespaceUri4}}${localName4}`;
|
|
4394
|
+
}
|
|
4395
|
+
function elementMatchesWildcard(elementLocalName, elementNamespace, wildcardNode, targetNamespace) {
|
|
4396
|
+
if (!wildcardNode || wildcardNode.kind !== "any") {
|
|
4397
|
+
return false;
|
|
4398
|
+
}
|
|
4399
|
+
if (!namespaceMatches(elementNamespace, wildcardNode.namespace, targetNamespace)) {
|
|
4400
|
+
return false;
|
|
4401
|
+
}
|
|
4402
|
+
if (isExcludedByNotNamespace(elementNamespace, wildcardNode.notNamespace)) {
|
|
4403
|
+
return false;
|
|
4404
|
+
}
|
|
4405
|
+
const qName = buildQName(elementLocalName, elementNamespace);
|
|
4406
|
+
if (isExcludedByNotQName(qName, wildcardNode.notQName)) {
|
|
4407
|
+
return false;
|
|
4408
|
+
}
|
|
4409
|
+
return true;
|
|
4410
|
+
}
|
|
4411
|
+
function attributeMatchesWildcard(attrLocalName, attrNamespace, wildcardNode, targetNamespace) {
|
|
4412
|
+
if (!wildcardNode || wildcardNode.kind !== "anyAttribute") {
|
|
4413
|
+
return false;
|
|
4414
|
+
}
|
|
4415
|
+
if (!namespaceMatches(attrNamespace, wildcardNode.namespace, targetNamespace)) {
|
|
4416
|
+
return false;
|
|
4417
|
+
}
|
|
4418
|
+
if (isExcludedByNotNamespace(attrNamespace, wildcardNode.notNamespace)) {
|
|
4419
|
+
return false;
|
|
4420
|
+
}
|
|
4421
|
+
const qName = buildQName(attrLocalName, attrNamespace);
|
|
4422
|
+
if (isExcludedByNotQName(qName, wildcardNode.notQName)) {
|
|
4423
|
+
return false;
|
|
4424
|
+
}
|
|
4425
|
+
return true;
|
|
4426
|
+
}
|
|
4427
|
+
function normalizeProcessContents(processContents) {
|
|
4428
|
+
if (processContents === "lax" || processContents === "skip") {
|
|
4429
|
+
return processContents;
|
|
4430
|
+
}
|
|
4431
|
+
return "strict";
|
|
4432
|
+
}
|
|
4433
|
+
function isStrictWildcardValidation(processContents) {
|
|
4434
|
+
return normalizeProcessContents(processContents) === "strict";
|
|
4435
|
+
}
|
|
4436
|
+
function shouldSkipWildcardValidation(processContents) {
|
|
4437
|
+
return normalizeProcessContents(processContents) === "skip";
|
|
4438
|
+
}
|
|
4439
|
+
|
|
3723
4440
|
// src/validation/structureValidator.js
|
|
3724
4441
|
function elementChildren2(xmlNode) {
|
|
3725
4442
|
return Array.from(xmlNode?.children || []).filter((child) => child.nodeType === 1);
|
|
@@ -3789,6 +4506,7 @@ function isSimpleContentComplexType(complexTypeDecl) {
|
|
|
3789
4506
|
function validateAttributes(xmlNode, attributes, context) {
|
|
3790
4507
|
const { schema, createIssue: createIssue2, ISSUE_CODES: ISSUE_CODES2, issues, pathParts, validateAttributeValue: validateAttributeValue2 } = context;
|
|
3791
4508
|
const allowed = /* @__PURE__ */ new Map();
|
|
4509
|
+
let anyAttributeWildcard = null;
|
|
3792
4510
|
for (const attr of attributes || []) {
|
|
3793
4511
|
if (!attr) continue;
|
|
3794
4512
|
if (attr.kind === "attribute") {
|
|
@@ -3800,6 +4518,8 @@ function validateAttributes(xmlNode, attributes, context) {
|
|
|
3800
4518
|
const group = context.resolveAttributeGroup?.(attr.refName);
|
|
3801
4519
|
if (!group) continue;
|
|
3802
4520
|
validateAttributes(xmlNode, group.attributes || [], context);
|
|
4521
|
+
} else if (attr.kind === "anyAttribute") {
|
|
4522
|
+
anyAttributeWildcard = attr;
|
|
3803
4523
|
}
|
|
3804
4524
|
}
|
|
3805
4525
|
for (const attrDecl of allowed.values()) {
|
|
@@ -3845,6 +4565,15 @@ function validateAttributes(xmlNode, attributes, context) {
|
|
|
3845
4565
|
continue;
|
|
3846
4566
|
}
|
|
3847
4567
|
if (!allowed.has(attr.name)) {
|
|
4568
|
+
if (anyAttributeWildcard) {
|
|
4569
|
+
const attrLocalName = attr.localName || attr.name.split(":")[1] || attr.name;
|
|
4570
|
+
const attrNamespace = attr.namespaceURI || null;
|
|
4571
|
+
if (attributeMatchesWildcard(attrLocalName, attrNamespace, anyAttributeWildcard, schema.targetNamespace)) {
|
|
4572
|
+
if (!shouldSkipWildcardValidation(anyAttributeWildcard.processContents)) {
|
|
4573
|
+
}
|
|
4574
|
+
continue;
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
3848
4577
|
issues.push(
|
|
3849
4578
|
createIssue2({
|
|
3850
4579
|
code: ISSUE_CODES2.XML_UNEXPECTED_ATTRIBUTE,
|
|
@@ -4262,7 +4991,16 @@ function validateContentModel(children, modelNode, context, pathParts, startInde
|
|
|
4262
4991
|
return validateAll(children, startIndex, modelNode, context, pathParts, silent);
|
|
4263
4992
|
case "any":
|
|
4264
4993
|
if (startIndex < children.length) {
|
|
4265
|
-
|
|
4994
|
+
const childNode = children[startIndex];
|
|
4995
|
+
const childLocalName = localName(childNode);
|
|
4996
|
+
const childNamespace = namespaceUri(childNode);
|
|
4997
|
+
if (elementMatchesWildcard(childLocalName, childNamespace, modelNode, context.schema.targetNamespace)) {
|
|
4998
|
+
if (isStrictWildcardValidation(modelNode.processContents)) {
|
|
4999
|
+
validateElementDecl(childNode, { name: childLocalName, typeName: null }, context, [...pathParts, childLocalName]);
|
|
5000
|
+
} else if (!shouldSkipWildcardValidation(modelNode.processContents)) {
|
|
5001
|
+
}
|
|
5002
|
+
return { nextIndex: startIndex + 1, matched: true, matchedAny: true };
|
|
5003
|
+
}
|
|
4266
5004
|
}
|
|
4267
5005
|
return { nextIndex: startIndex, matched: true, matchedAny: false };
|
|
4268
5006
|
default:
|
|
@@ -4270,6 +5008,461 @@ function validateContentModel(children, modelNode, context, pathParts, startInde
|
|
|
4270
5008
|
}
|
|
4271
5009
|
}
|
|
4272
5010
|
|
|
5011
|
+
// src/utils/xpathEvaluator.js
|
|
5012
|
+
function nodeMatchesQName(schema, node, qName) {
|
|
5013
|
+
if (!node || !qName) return false;
|
|
5014
|
+
const parsed = parseQName(qName);
|
|
5015
|
+
const expectedNs = resolveNamespaceUri(schema, parsed.prefix);
|
|
5016
|
+
const nodeLocal = node.localName || node.nodeName || null;
|
|
5017
|
+
const nodeNs = node.namespaceURI || null;
|
|
5018
|
+
if (parsed.prefix) {
|
|
5019
|
+
let nsToCompare = expectedNs || null;
|
|
5020
|
+
if (!nsToCompare) {
|
|
5021
|
+
if (typeof node.lookupNamespaceURI === "function") {
|
|
5022
|
+
try {
|
|
5023
|
+
nsToCompare = node.lookupNamespaceURI(parsed.prefix) || null;
|
|
5024
|
+
} catch (e) {
|
|
5025
|
+
nsToCompare = null;
|
|
5026
|
+
}
|
|
5027
|
+
}
|
|
5028
|
+
if (!nsToCompare && node.prefix) {
|
|
5029
|
+
return nodeLocal === parsed.localName && node.prefix === parsed.prefix;
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
return nodeLocal === parsed.localName && (nodeNs || null) === (nsToCompare || null);
|
|
5033
|
+
}
|
|
5034
|
+
return nodeLocal === parsed.localName;
|
|
5035
|
+
}
|
|
5036
|
+
function collectDescendants(node, predicate) {
|
|
5037
|
+
const matches = [];
|
|
5038
|
+
function traverse(n) {
|
|
5039
|
+
if (!n || n.nodeType !== 1) return;
|
|
5040
|
+
if (predicate(n)) matches.push(n);
|
|
5041
|
+
for (const child of Array.from(n.childNodes || [])) {
|
|
5042
|
+
traverse(child);
|
|
5043
|
+
}
|
|
5044
|
+
}
|
|
5045
|
+
traverse(node);
|
|
5046
|
+
return matches;
|
|
5047
|
+
}
|
|
5048
|
+
function evaluateSelector(schema, startNodes, selectorXPath) {
|
|
5049
|
+
if (!selectorXPath || !Array.isArray(startNodes) || startNodes.length === 0) return [];
|
|
5050
|
+
let xpath = selectorXPath.trim();
|
|
5051
|
+
if (xpath.startsWith("./")) xpath = xpath.slice(2);
|
|
5052
|
+
if (xpath === "." || xpath === "") return startNodes;
|
|
5053
|
+
if (xpath.includes("//")) {
|
|
5054
|
+
return evaluateSelectorWithDescendant(schema, startNodes, xpath);
|
|
5055
|
+
}
|
|
5056
|
+
const segments = xpath.split("/");
|
|
5057
|
+
let nodes = startNodes;
|
|
5058
|
+
for (const raw of segments) {
|
|
5059
|
+
if (!raw || raw === ".") continue;
|
|
5060
|
+
const m = raw.match(/^([^\[]+)(?:\[(.+)\])?$/);
|
|
5061
|
+
if (!m) return [];
|
|
5062
|
+
const step = m[1];
|
|
5063
|
+
const predicate = m[2] || null;
|
|
5064
|
+
if (step === "*") {
|
|
5065
|
+
nodes = nodes.flatMap((n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1));
|
|
5066
|
+
} else if (step.startsWith("@")) {
|
|
5067
|
+
return [];
|
|
5068
|
+
} else {
|
|
5069
|
+
nodes = nodes.flatMap(
|
|
5070
|
+
(n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => {
|
|
5071
|
+
return nodeMatchesQName(schema, c, step);
|
|
5072
|
+
})
|
|
5073
|
+
);
|
|
5074
|
+
if (predicate && nodes.length) {
|
|
5075
|
+
const num = Number(predicate);
|
|
5076
|
+
if (Number.isInteger(num) && num > 0) {
|
|
5077
|
+
const idx = num - 1;
|
|
5078
|
+
nodes = nodes.length > idx ? [nodes[idx]] : [];
|
|
5079
|
+
} else {
|
|
5080
|
+
const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
|
|
5081
|
+
if (attrMatch) {
|
|
5082
|
+
const attrName = attrMatch[1];
|
|
5083
|
+
const attrValue = attrMatch[2];
|
|
5084
|
+
nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
|
|
5085
|
+
} else {
|
|
5086
|
+
nodes = [];
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5090
|
+
}
|
|
5091
|
+
}
|
|
5092
|
+
return nodes;
|
|
5093
|
+
}
|
|
5094
|
+
function evaluateSelectorWithDescendant(schema, startNodes, xpath) {
|
|
5095
|
+
const fullParts = xpath.split(/\/\//);
|
|
5096
|
+
let nodes = startNodes;
|
|
5097
|
+
for (let partIdx = 0; partIdx < fullParts.length; partIdx++) {
|
|
5098
|
+
const part = fullParts[partIdx].trim();
|
|
5099
|
+
if (!part) continue;
|
|
5100
|
+
if (partIdx === 0) {
|
|
5101
|
+
if (part !== ".") {
|
|
5102
|
+
const segments = part.split("/");
|
|
5103
|
+
for (const seg of segments) {
|
|
5104
|
+
if (!seg || seg === ".") continue;
|
|
5105
|
+
const m = seg.match(/^([^\[]+)(?:\[(.+)\])?$/);
|
|
5106
|
+
if (!m) return [];
|
|
5107
|
+
const step = m[1];
|
|
5108
|
+
const predicate = m[2] || null;
|
|
5109
|
+
if (step === "*") {
|
|
5110
|
+
nodes = nodes.flatMap((n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1));
|
|
5111
|
+
} else if (step.startsWith("@")) {
|
|
5112
|
+
return [];
|
|
5113
|
+
} else {
|
|
5114
|
+
nodes = nodes.flatMap(
|
|
5115
|
+
(n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => nodeMatchesQName(schema, c, step))
|
|
5116
|
+
);
|
|
5117
|
+
if (predicate && nodes.length) {
|
|
5118
|
+
const num = Number(predicate);
|
|
5119
|
+
if (Number.isInteger(num) && num > 0) {
|
|
5120
|
+
const idx = num - 1;
|
|
5121
|
+
nodes = nodes.length > idx ? [nodes[idx]] : [];
|
|
5122
|
+
} else {
|
|
5123
|
+
const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
|
|
5124
|
+
if (attrMatch) {
|
|
5125
|
+
const attrName = attrMatch[1];
|
|
5126
|
+
const attrValue = attrMatch[2];
|
|
5127
|
+
nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
|
|
5128
|
+
} else {
|
|
5129
|
+
nodes = [];
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
}
|
|
5135
|
+
}
|
|
5136
|
+
} else {
|
|
5137
|
+
const segments = part.split("/");
|
|
5138
|
+
for (let segIdx = 0; segIdx < segments.length; segIdx++) {
|
|
5139
|
+
const segment = segments[segIdx];
|
|
5140
|
+
if (!segment || segment === ".") continue;
|
|
5141
|
+
const m = segment.match(/^([^\[]+)(?:\[(.+)\])?$/);
|
|
5142
|
+
if (!m) return [];
|
|
5143
|
+
const step = m[1];
|
|
5144
|
+
const predicate = m[2] || null;
|
|
5145
|
+
if (segIdx === 0) {
|
|
5146
|
+
const descendants = [];
|
|
5147
|
+
for (const node of nodes) {
|
|
5148
|
+
const matches = collectDescendants(node, (n) => {
|
|
5149
|
+
if (step === "*") return true;
|
|
5150
|
+
if (step.startsWith("@")) return false;
|
|
5151
|
+
return nodeMatchesQName(schema, n, step);
|
|
5152
|
+
});
|
|
5153
|
+
descendants.push(...matches);
|
|
5154
|
+
}
|
|
5155
|
+
nodes = descendants;
|
|
5156
|
+
if (predicate && nodes.length) {
|
|
5157
|
+
const predicateMatch = predicate.match(/^\[(.+)\]$/);
|
|
5158
|
+
if (predicateMatch) {
|
|
5159
|
+
const pred = predicateMatch[1];
|
|
5160
|
+
const num = Number(pred);
|
|
5161
|
+
if (Number.isInteger(num) && num > 0) {
|
|
5162
|
+
const idx = num - 1;
|
|
5163
|
+
nodes = nodes.length > idx ? [nodes[idx]] : [];
|
|
5164
|
+
} else {
|
|
5165
|
+
const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
|
|
5166
|
+
if (attrMatch) {
|
|
5167
|
+
const attrName = attrMatch[1];
|
|
5168
|
+
const attrValue = attrMatch[2];
|
|
5169
|
+
nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
|
|
5170
|
+
} else {
|
|
5171
|
+
nodes = [];
|
|
5172
|
+
}
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
}
|
|
5176
|
+
} else {
|
|
5177
|
+
nodes = nodes.flatMap(
|
|
5178
|
+
(n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => {
|
|
5179
|
+
if (step === "*") return true;
|
|
5180
|
+
if (step.startsWith("@")) return false;
|
|
5181
|
+
return nodeMatchesQName(schema, c, step);
|
|
5182
|
+
})
|
|
5183
|
+
);
|
|
5184
|
+
if (predicate && nodes.length) {
|
|
5185
|
+
const predicateMatch = predicate.match(/^\[(.+)\]$/);
|
|
5186
|
+
if (predicateMatch) {
|
|
5187
|
+
const pred = predicateMatch[1];
|
|
5188
|
+
const num = Number(pred);
|
|
5189
|
+
if (Number.isInteger(num) && num > 0) {
|
|
5190
|
+
const idx = num - 1;
|
|
5191
|
+
nodes = nodes.length > idx ? [nodes[idx]] : [];
|
|
5192
|
+
} else {
|
|
5193
|
+
const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
|
|
5194
|
+
if (attrMatch) {
|
|
5195
|
+
const attrName = attrMatch[1];
|
|
5196
|
+
const attrValue = attrMatch[2];
|
|
5197
|
+
nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
|
|
5198
|
+
} else {
|
|
5199
|
+
nodes = [];
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
}
|
|
5207
|
+
if (!nodes.length && partIdx < fullParts.length - 1) {
|
|
5208
|
+
return [];
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
return nodes;
|
|
5212
|
+
}
|
|
5213
|
+
function evaluateField(schema, contextNode, fieldXPath) {
|
|
5214
|
+
if (!fieldXPath || !contextNode) return null;
|
|
5215
|
+
let xpath = fieldXPath.trim();
|
|
5216
|
+
if (xpath.startsWith("./")) xpath = xpath.slice(2);
|
|
5217
|
+
if (xpath === ".") return (contextNode.textContent || "").trim() || null;
|
|
5218
|
+
if (xpath.startsWith("@")) {
|
|
5219
|
+
const attr = xpath.slice(1);
|
|
5220
|
+
return contextNode.getAttribute(attr) ?? null;
|
|
5221
|
+
}
|
|
5222
|
+
if (xpath.includes("//")) {
|
|
5223
|
+
return evaluateFieldWithDescendant(schema, contextNode, xpath);
|
|
5224
|
+
}
|
|
5225
|
+
const segments = xpath.split("/");
|
|
5226
|
+
let nodes = [contextNode];
|
|
5227
|
+
for (let i = 0; i < segments.length; i += 1) {
|
|
5228
|
+
const raw = segments[i];
|
|
5229
|
+
if (!raw || raw === ".") continue;
|
|
5230
|
+
const m = raw.match(/^([^\[]+)(?:\[(.+)\])?$/);
|
|
5231
|
+
if (!m) return null;
|
|
5232
|
+
const step = m[1];
|
|
5233
|
+
const predicate = m[2] || null;
|
|
5234
|
+
if (step.startsWith("@")) {
|
|
5235
|
+
if (i !== segments.length - 1) return null;
|
|
5236
|
+
return nodes[0]?.getAttribute(step.slice(1)) ?? null;
|
|
5237
|
+
}
|
|
5238
|
+
nodes = nodes.flatMap(
|
|
5239
|
+
(n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1 && nodeMatchesQName(schema, c, step))
|
|
5240
|
+
);
|
|
5241
|
+
if (!nodes.length) return null;
|
|
5242
|
+
if (predicate) {
|
|
5243
|
+
const num = Number(predicate);
|
|
5244
|
+
if (Number.isInteger(num) && num > 0) {
|
|
5245
|
+
const idx = num - 1;
|
|
5246
|
+
nodes = nodes.length > idx ? [nodes[idx]] : [];
|
|
5247
|
+
} else {
|
|
5248
|
+
const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
|
|
5249
|
+
if (attrMatch) {
|
|
5250
|
+
const attrName = attrMatch[1];
|
|
5251
|
+
const attrValue = attrMatch[2];
|
|
5252
|
+
nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
|
|
5253
|
+
} else {
|
|
5254
|
+
return null;
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
const v = nodes[0];
|
|
5260
|
+
if (!v) return null;
|
|
5261
|
+
return (v.textContent || "").trim() || null;
|
|
5262
|
+
}
|
|
5263
|
+
function evaluateFieldWithDescendant(schema, contextNode, xpath) {
|
|
5264
|
+
const parts = xpath.split(/\/\//);
|
|
5265
|
+
let nodes = [contextNode];
|
|
5266
|
+
for (let i = 0; i < parts.length; i++) {
|
|
5267
|
+
const part = parts[i].trim();
|
|
5268
|
+
if (!part) continue;
|
|
5269
|
+
if (i === 0) {
|
|
5270
|
+
if (part !== "." && part !== "") {
|
|
5271
|
+
const val = evaluateField(schema, nodes[0], part);
|
|
5272
|
+
if (val !== null) return val;
|
|
5273
|
+
nodes = [];
|
|
5274
|
+
}
|
|
5275
|
+
} else {
|
|
5276
|
+
const m = part.match(/^([^\[]+)(?:\[(.+)\])?/);
|
|
5277
|
+
if (!m) return null;
|
|
5278
|
+
const step = m[1];
|
|
5279
|
+
const predicate = part.slice(m[0].length);
|
|
5280
|
+
if (step.startsWith("@")) {
|
|
5281
|
+
const attrName = step.slice(1);
|
|
5282
|
+
for (const node of nodes) {
|
|
5283
|
+
const descendants2 = collectDescendants(node, () => true);
|
|
5284
|
+
if (descendants2.length) {
|
|
5285
|
+
return descendants2[0]?.getAttribute(attrName) ?? null;
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
return null;
|
|
5289
|
+
}
|
|
5290
|
+
const descendants = [];
|
|
5291
|
+
for (const node of nodes) {
|
|
5292
|
+
descendants.push(
|
|
5293
|
+
...collectDescendants(node, (n) => {
|
|
5294
|
+
if (step === "*") return true;
|
|
5295
|
+
return nodeMatchesQName(schema, n, step);
|
|
5296
|
+
})
|
|
5297
|
+
);
|
|
5298
|
+
}
|
|
5299
|
+
nodes = descendants;
|
|
5300
|
+
if (!nodes.length) return null;
|
|
5301
|
+
if (predicate) {
|
|
5302
|
+
const predicateMatch = predicate.match(/^\[(.+)\]$/);
|
|
5303
|
+
if (predicateMatch) {
|
|
5304
|
+
const pred = predicateMatch[1];
|
|
5305
|
+
const num = Number(pred);
|
|
5306
|
+
if (Number.isInteger(num) && num > 0) {
|
|
5307
|
+
const idx = num - 1;
|
|
5308
|
+
nodes = nodes.length > idx ? [nodes[idx]] : [];
|
|
5309
|
+
} else {
|
|
5310
|
+
const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
|
|
5311
|
+
if (attrMatch) {
|
|
5312
|
+
const attrName = attrMatch[1];
|
|
5313
|
+
const attrValue = attrMatch[2];
|
|
5314
|
+
nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
if (nodes.length) {
|
|
5320
|
+
const v = nodes[0];
|
|
5321
|
+
return (v.textContent || "").trim() || null;
|
|
5322
|
+
}
|
|
5323
|
+
}
|
|
5324
|
+
}
|
|
5325
|
+
return null;
|
|
5326
|
+
}
|
|
5327
|
+
|
|
5328
|
+
// src/validation/identityConstraintValidator.js
|
|
5329
|
+
function localName2(node) {
|
|
5330
|
+
return node?.localName || node?.nodeName || null;
|
|
5331
|
+
}
|
|
5332
|
+
function namespaceUri2(node) {
|
|
5333
|
+
return node?.namespaceURI || null;
|
|
5334
|
+
}
|
|
5335
|
+
function collectOwnerXmlNodes(xmlRoot, ownerName, ownerNamespaceUri) {
|
|
5336
|
+
const matches = [];
|
|
5337
|
+
function traverse(node) {
|
|
5338
|
+
if (!node || node.nodeType !== 1) return;
|
|
5339
|
+
if (localName2(node) === ownerName && (ownerNamespaceUri == null || ownerNamespaceUri === namespaceUri2(node))) {
|
|
5340
|
+
matches.push(node);
|
|
5341
|
+
}
|
|
5342
|
+
for (const child of Array.from(node.children || [])) {
|
|
5343
|
+
traverse(child);
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5346
|
+
traverse(xmlRoot);
|
|
5347
|
+
return matches;
|
|
5348
|
+
}
|
|
5349
|
+
function getConstraintOwnerNodes(schema, xmlRoot, constraint) {
|
|
5350
|
+
if (!constraint.ownerName) {
|
|
5351
|
+
return [xmlRoot];
|
|
5352
|
+
}
|
|
5353
|
+
return collectOwnerXmlNodes(
|
|
5354
|
+
xmlRoot,
|
|
5355
|
+
constraint.ownerName,
|
|
5356
|
+
constraint.ownerNamespaceUri
|
|
5357
|
+
);
|
|
5358
|
+
}
|
|
5359
|
+
function validateIdentityConstraints(schema, xmlRoot, getNodeLocation) {
|
|
5360
|
+
const issues = [];
|
|
5361
|
+
const keySets = /* @__PURE__ */ new Map();
|
|
5362
|
+
function buildKeySet(constraint) {
|
|
5363
|
+
if (keySets.has(constraint.name)) {
|
|
5364
|
+
return keySets.get(constraint.name);
|
|
5365
|
+
}
|
|
5366
|
+
const set = /* @__PURE__ */ new Set();
|
|
5367
|
+
const ownerNodes = getConstraintOwnerNodes(schema, xmlRoot, constraint);
|
|
5368
|
+
for (const ownerNode of ownerNodes) {
|
|
5369
|
+
const selected = evaluateSelector(schema, [ownerNode], constraint.selector?.xpath);
|
|
5370
|
+
for (const selectedNode of selected) {
|
|
5371
|
+
const tuple = constraint.fields.map((field) => evaluateField(schema, selectedNode, field.xpath));
|
|
5372
|
+
set.add(JSON.stringify(tuple));
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
keySets.set(constraint.name, set);
|
|
5376
|
+
return set;
|
|
5377
|
+
}
|
|
5378
|
+
for (const constraint of schema.identityConstraints || []) {
|
|
5379
|
+
const ownerNodes = getConstraintOwnerNodes(schema, xmlRoot, constraint);
|
|
5380
|
+
if (!ownerNodes.length) {
|
|
5381
|
+
continue;
|
|
5382
|
+
}
|
|
5383
|
+
const valueIndex = /* @__PURE__ */ new Map();
|
|
5384
|
+
const referenceKeyConstraint = schema.identityConstraints.find(
|
|
5385
|
+
(item) => item.kind === "key" && item.name === parseQName(constraint.refer || "").localName
|
|
5386
|
+
);
|
|
5387
|
+
const referenceKeySet = constraint.kind === "keyref" && referenceKeyConstraint ? buildKeySet(referenceKeyConstraint) : null;
|
|
5388
|
+
for (const ownerNode of ownerNodes) {
|
|
5389
|
+
const selected = evaluateSelector(schema, [ownerNode], constraint.selector?.xpath);
|
|
5390
|
+
for (const selectedNode of selected) {
|
|
5391
|
+
const tuple = constraint.fields.map((field) => evaluateField(schema, selectedNode, field.xpath));
|
|
5392
|
+
const tupleKey = JSON.stringify(tuple);
|
|
5393
|
+
const rawLocation = getNodeLocation ? getNodeLocation(selectedNode) : null;
|
|
5394
|
+
const location = rawLocation || { line: constraint.line || 1, column: constraint.column || 1 };
|
|
5395
|
+
if (tuple.some((value) => value == null || value === "")) {
|
|
5396
|
+
if (constraint.kind === "key") {
|
|
5397
|
+
issues.push(
|
|
5398
|
+
createIssue({
|
|
5399
|
+
code: ISSUE_CODES.XML_KEY_NULL_VIOLATION,
|
|
5400
|
+
severity: "error",
|
|
5401
|
+
message: `xs:key '${constraint.name}' requires non-empty values for all fields.`,
|
|
5402
|
+
line: location.line,
|
|
5403
|
+
column: location.column,
|
|
5404
|
+
path: constraint.path,
|
|
5405
|
+
source: "xml",
|
|
5406
|
+
nodeKind: "element",
|
|
5407
|
+
name: constraint.name,
|
|
5408
|
+
details: {
|
|
5409
|
+
selector: constraint.selector?.xpath,
|
|
5410
|
+
fields: constraint.fields.map((field) => field.xpath)
|
|
5411
|
+
}
|
|
5412
|
+
})
|
|
5413
|
+
);
|
|
5414
|
+
}
|
|
5415
|
+
}
|
|
5416
|
+
if (constraint.kind === "key" || constraint.kind === "unique") {
|
|
5417
|
+
if (valueIndex.has(tupleKey)) {
|
|
5418
|
+
issues.push(
|
|
5419
|
+
createIssue({
|
|
5420
|
+
code: constraint.kind === "key" ? ISSUE_CODES.XML_KEY_VIOLATION : ISSUE_CODES.XML_UNIQUE_VIOLATION,
|
|
5421
|
+
severity: "error",
|
|
5422
|
+
message: `Duplicate ${constraint.kind} value for '${constraint.name}'.`,
|
|
5423
|
+
line: location.line,
|
|
5424
|
+
column: location.column,
|
|
5425
|
+
path: constraint.path,
|
|
5426
|
+
source: "xml",
|
|
5427
|
+
nodeKind: "element",
|
|
5428
|
+
name: constraint.name,
|
|
5429
|
+
details: {
|
|
5430
|
+
selector: constraint.selector?.xpath,
|
|
5431
|
+
fields: constraint.fields.map((field) => field.xpath)
|
|
5432
|
+
}
|
|
5433
|
+
})
|
|
5434
|
+
);
|
|
5435
|
+
}
|
|
5436
|
+
valueIndex.set(tupleKey, true);
|
|
5437
|
+
}
|
|
5438
|
+
if (constraint.kind === "keyref" && referenceKeySet) {
|
|
5439
|
+
if (!referenceKeySet.has(tupleKey)) {
|
|
5440
|
+
issues.push(
|
|
5441
|
+
createIssue({
|
|
5442
|
+
code: ISSUE_CODES.XML_KEYREF_VIOLATION,
|
|
5443
|
+
severity: "error",
|
|
5444
|
+
message: `xs:keyref '${constraint.name}' references a missing key value.`,
|
|
5445
|
+
line: location.line,
|
|
5446
|
+
column: location.column,
|
|
5447
|
+
path: constraint.path,
|
|
5448
|
+
source: "xml",
|
|
5449
|
+
nodeKind: "element",
|
|
5450
|
+
name: constraint.name,
|
|
5451
|
+
details: {
|
|
5452
|
+
refer: constraint.refer,
|
|
5453
|
+
selector: constraint.selector?.xpath,
|
|
5454
|
+
fields: constraint.fields.map((field) => field.xpath)
|
|
5455
|
+
}
|
|
5456
|
+
})
|
|
5457
|
+
);
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
}
|
|
5463
|
+
return issues;
|
|
5464
|
+
}
|
|
5465
|
+
|
|
4273
5466
|
// src/validation/builtinTypeValidators.js
|
|
4274
5467
|
function isIntegerString(value) {
|
|
4275
5468
|
return /^[-+]?\d+$/.test(value);
|
|
@@ -4767,12 +5960,12 @@ function findAttributeValueOffset(tagText, attrName) {
|
|
|
4767
5960
|
const end = tagText.indexOf(quoteChar, start);
|
|
4768
5961
|
return end >= start ? start : -1;
|
|
4769
5962
|
}
|
|
4770
|
-
function findTextContentOffset(text, tagEndOffset,
|
|
5963
|
+
function findTextContentOffset(text, tagEndOffset, localName4) {
|
|
4771
5964
|
let i = tagEndOffset + 1;
|
|
4772
5965
|
while (i < text.length && /\s/.test(text[i])) {
|
|
4773
5966
|
i += 1;
|
|
4774
5967
|
}
|
|
4775
|
-
if (text.startsWith(`</${
|
|
5968
|
+
if (text.startsWith(`</${localName4}`, i) || text[i] === "<") {
|
|
4776
5969
|
return -1;
|
|
4777
5970
|
}
|
|
4778
5971
|
return i < text.length ? i : -1;
|
|
@@ -4799,10 +5992,20 @@ function createXmlSourceLocator(xmlText, xmlDocument) {
|
|
|
4799
5992
|
}
|
|
4800
5993
|
};
|
|
4801
5994
|
}
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
...Array.from(documentElement.querySelectorAll("*"))
|
|
4805
|
-
|
|
5995
|
+
let orderedNodes = null;
|
|
5996
|
+
if (typeof documentElement.querySelectorAll === "function") {
|
|
5997
|
+
orderedNodes = [documentElement, ...Array.from(documentElement.querySelectorAll("*"))];
|
|
5998
|
+
} else {
|
|
5999
|
+
let collect = function(node) {
|
|
6000
|
+
if (!node || node.nodeType !== 1) return;
|
|
6001
|
+
orderedNodes.push(node);
|
|
6002
|
+
for (const child of Array.from(node.children || [])) {
|
|
6003
|
+
collect(child);
|
|
6004
|
+
}
|
|
6005
|
+
};
|
|
6006
|
+
orderedNodes = [];
|
|
6007
|
+
collect(documentElement);
|
|
6008
|
+
}
|
|
4806
6009
|
let searchFrom = 0;
|
|
4807
6010
|
for (const node of orderedNodes) {
|
|
4808
6011
|
const expectedLocalName = getNodeLocalName(node);
|
|
@@ -4879,10 +6082,10 @@ function elementChildren3(xmlNode) {
|
|
|
4879
6082
|
(child) => child.nodeType === 1
|
|
4880
6083
|
);
|
|
4881
6084
|
}
|
|
4882
|
-
function
|
|
6085
|
+
function localName3(node) {
|
|
4883
6086
|
return node?.localName || node?.nodeName || null;
|
|
4884
6087
|
}
|
|
4885
|
-
function
|
|
6088
|
+
function namespaceUri3(node) {
|
|
4886
6089
|
return node?.namespaceURI || null;
|
|
4887
6090
|
}
|
|
4888
6091
|
function determineRootElement(schema, xmlRootName, xmlRootNs, options) {
|
|
@@ -4927,8 +6130,8 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
|
|
|
4927
6130
|
}
|
|
4928
6131
|
const locator = createXmlSourceLocator(xmlText, xmlParse.document);
|
|
4929
6132
|
const xmlRoot = xmlParse.document.documentElement;
|
|
4930
|
-
const xmlRootName =
|
|
4931
|
-
const xmlRootNs =
|
|
6133
|
+
const xmlRootName = localName3(xmlRoot);
|
|
6134
|
+
const xmlRootNs = namespaceUri3(xmlRoot);
|
|
4932
6135
|
const issues = [...parseIssues];
|
|
4933
6136
|
if (!xmlRoot) {
|
|
4934
6137
|
return {
|
|
@@ -5048,7 +6251,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
|
|
|
5048
6251
|
const children2 = elementChildren3(xmlRoot);
|
|
5049
6252
|
if (children2.length > 0) {
|
|
5050
6253
|
for (const childNode of children2) {
|
|
5051
|
-
const childName =
|
|
6254
|
+
const childName = localName3(childNode);
|
|
5052
6255
|
issues.push(
|
|
5053
6256
|
createIssue({
|
|
5054
6257
|
code: ISSUE_CODES.XML_UNEXPECTED_ELEMENT,
|
|
@@ -5060,7 +6263,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
|
|
|
5060
6263
|
nodeKind: "element",
|
|
5061
6264
|
name: childName,
|
|
5062
6265
|
details: {
|
|
5063
|
-
namespaceUri:
|
|
6266
|
+
namespaceUri: namespaceUri3(childNode)
|
|
5064
6267
|
}
|
|
5065
6268
|
})
|
|
5066
6269
|
);
|
|
@@ -5137,7 +6340,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
|
|
|
5137
6340
|
if (result.nextIndex < children.length) {
|
|
5138
6341
|
for (let i = result.nextIndex; i < children.length; i += 1) {
|
|
5139
6342
|
const childNode = children[i];
|
|
5140
|
-
const childName =
|
|
6343
|
+
const childName = localName3(childNode);
|
|
5141
6344
|
issues.push(
|
|
5142
6345
|
createIssue({
|
|
5143
6346
|
code: ISSUE_CODES.XML_UNEXPECTED_ELEMENT,
|
|
@@ -5149,7 +6352,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
|
|
|
5149
6352
|
nodeKind: "element",
|
|
5150
6353
|
name: childName,
|
|
5151
6354
|
details: {
|
|
5152
|
-
namespaceUri:
|
|
6355
|
+
namespaceUri: namespaceUri3(childNode)
|
|
5153
6356
|
}
|
|
5154
6357
|
})
|
|
5155
6358
|
);
|
|
@@ -5180,6 +6383,12 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
|
|
|
5180
6383
|
);
|
|
5181
6384
|
}
|
|
5182
6385
|
}
|
|
6386
|
+
const identityConstraintIssues = validateIdentityConstraints(
|
|
6387
|
+
schema,
|
|
6388
|
+
xmlRoot,
|
|
6389
|
+
locator.getNodeLocation
|
|
6390
|
+
);
|
|
6391
|
+
issues.push(...identityConstraintIssues);
|
|
5183
6392
|
return {
|
|
5184
6393
|
data: {
|
|
5185
6394
|
xmlValid: !issues.some((issue) => issue.severity === "error")
|