moxml 0.5.175 → 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/Rakefile +37 -5
- data/conformance/moxml-conformance.json +627 -2
- data/lib/moxml/context.rb +9 -5
- data/lib/moxml/entity_registry.rb +52 -0
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml/xsd/schema_rules.rb +127 -7
- data/lib/moxml/xsd.rb +6 -2
- data/lib/moxml.rb +1 -1
- data/spec/moxml/entity_registry_conformance_spec.rb +54 -0
- data/spec/moxml/signature_autoload_spec.rb +52 -0
- data/spec/moxml/wildcard_conformance_spec.rb +48 -0
- data/spec/moxml/xsd_regex_conformance_spec.rb +36 -0
- data/spec/moxml/xsd_set_spec.rb +78 -0
- metadata +5 -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/Rakefile
CHANGED
|
@@ -355,13 +355,44 @@ namespace :conformance do
|
|
|
355
355
|
task :export do
|
|
356
356
|
require "json"
|
|
357
357
|
require_relative "lib/moxml"
|
|
358
|
-
|
|
358
|
+
lexical = Moxml::XSD::BuiltinLexical::CONFORMANCE_CASES
|
|
359
|
+
regex = Moxml::XSD::SchemaRules::XsdRegex::CONFORMANCE_CASES
|
|
360
|
+
wildcards = Moxml::XSD::SchemaRules::Wildcard::WILDCARD_CASES
|
|
361
|
+
entities = Moxml::EntityRegistry::ENTITY_CONFORMANCE_CASES
|
|
359
362
|
payload = {
|
|
360
|
-
schema:
|
|
363
|
+
schema: 3,
|
|
361
364
|
generator: "moxml #{Moxml::VERSION}",
|
|
362
365
|
cases: {
|
|
363
|
-
"builtin_lexical" =>
|
|
364
|
-
{ "type" => type, "lexical" =>
|
|
366
|
+
"builtin_lexical" => lexical.map do |type, lexical_value, expected|
|
|
367
|
+
{ "type" => type, "lexical" => lexical_value, "valid" => expected }
|
|
368
|
+
end,
|
|
369
|
+
"xsd_regex_translation" => regex.map do |pattern, value, matches, translatable|
|
|
370
|
+
{
|
|
371
|
+
"pattern" => pattern, "value" => value,
|
|
372
|
+
"matches" => matches, "translatable" => translatable
|
|
373
|
+
}
|
|
374
|
+
end,
|
|
375
|
+
"schema_wildcards" => wildcards.map do |row|
|
|
376
|
+
constraint, process, not_namespace, not_qname, item_ns, item_qname,
|
|
377
|
+
defined, sibling_names, covers, exclusion = row
|
|
378
|
+
{
|
|
379
|
+
"constraint" => constraint, "process" => process,
|
|
380
|
+
"not_namespace" => not_namespace, "not_qname" => not_qname,
|
|
381
|
+
"item_namespace" => item_ns, "item_qname" => item_qname,
|
|
382
|
+
"defined" => defined, "sibling_names" => sibling_names,
|
|
383
|
+
"covers" => covers, "exclusion" => exclusion
|
|
384
|
+
}
|
|
385
|
+
end,
|
|
386
|
+
"entity_registry" => entities.map do |row|
|
|
387
|
+
seed, qname, qcp, restore_entities, mode, declared, codepoint,
|
|
388
|
+
names, primary, standard, restore = row
|
|
389
|
+
{
|
|
390
|
+
"seed" => seed, "qname" => qname, "qcp" => qcp,
|
|
391
|
+
"restore_entities" => restore_entities, "mode" => mode,
|
|
392
|
+
"declared" => declared, "codepoint" => codepoint,
|
|
393
|
+
"names" => names, "primary" => primary,
|
|
394
|
+
"standard" => standard, "restore" => restore
|
|
395
|
+
}
|
|
365
396
|
end,
|
|
366
397
|
},
|
|
367
398
|
}
|
|
@@ -369,7 +400,8 @@ namespace :conformance do
|
|
|
369
400
|
FileUtils.mkdir_p(dir)
|
|
370
401
|
target = File.join(dir, "moxml-conformance.json")
|
|
371
402
|
File.write(target, "#{JSON.pretty_generate(payload)}\n")
|
|
372
|
-
|
|
403
|
+
total = lexical.size + regex.size + wildcards.size + entities.size
|
|
404
|
+
puts "conformance: exported #{total} cases to #{target}"
|
|
373
405
|
end
|
|
374
406
|
end
|
|
375
407
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schema":
|
|
3
|
-
"generator": "moxml 0.5.
|
|
2
|
+
"schema": 3,
|
|
3
|
+
"generator": "moxml 0.5.175",
|
|
4
4
|
"cases": {
|
|
5
5
|
"builtin_lexical": [
|
|
6
6
|
{
|
|
@@ -408,6 +408,631 @@
|
|
|
408
408
|
"lexical": "a:b",
|
|
409
409
|
"valid": false
|
|
410
410
|
}
|
|
411
|
+
],
|
|
412
|
+
"xsd_regex_translation": [
|
|
413
|
+
{
|
|
414
|
+
"pattern": "\\p{IsBasicLatin}+",
|
|
415
|
+
"value": "abc",
|
|
416
|
+
"matches": true,
|
|
417
|
+
"translatable": true
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
"pattern": "\\p{IsBasicLatin}+",
|
|
421
|
+
"value": "",
|
|
422
|
+
"matches": false,
|
|
423
|
+
"translatable": true
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"pattern": "\\P{IsLatin-1Supplement}",
|
|
427
|
+
"value": "a",
|
|
428
|
+
"matches": true,
|
|
429
|
+
"translatable": true
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"pattern": "\\P{IsLatin-1Supplement}",
|
|
433
|
+
"value": "é",
|
|
434
|
+
"matches": false,
|
|
435
|
+
"translatable": true
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"pattern": "\\p{IsGreek}",
|
|
439
|
+
"value": "α",
|
|
440
|
+
"matches": true,
|
|
441
|
+
"translatable": true
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"pattern": "\\p{IsGreek}",
|
|
445
|
+
"value": "a",
|
|
446
|
+
"matches": false,
|
|
447
|
+
"translatable": true
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"pattern": "\\p{L}",
|
|
451
|
+
"value": "a",
|
|
452
|
+
"matches": true,
|
|
453
|
+
"translatable": true
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"pattern": "\\p{L}",
|
|
457
|
+
"value": "1",
|
|
458
|
+
"matches": false,
|
|
459
|
+
"translatable": true
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
"pattern": "\\p{Nd}{1,3}",
|
|
463
|
+
"value": "5",
|
|
464
|
+
"matches": true,
|
|
465
|
+
"translatable": true
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
"pattern": "\\p{Nd}{1,3}",
|
|
469
|
+
"value": "abc",
|
|
470
|
+
"matches": false,
|
|
471
|
+
"translatable": true
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
"pattern": "\\d{1,3}",
|
|
475
|
+
"value": "5",
|
|
476
|
+
"matches": false,
|
|
477
|
+
"translatable": false
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
"pattern": "\\d{1,3}",
|
|
481
|
+
"value": "abc",
|
|
482
|
+
"matches": false,
|
|
483
|
+
"translatable": false
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
"pattern": "[0-9]{1,3}",
|
|
487
|
+
"value": "42",
|
|
488
|
+
"matches": true,
|
|
489
|
+
"translatable": true
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
"pattern": "[a-z]*",
|
|
493
|
+
"value": "",
|
|
494
|
+
"matches": true,
|
|
495
|
+
"translatable": true
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"pattern": "a|b",
|
|
499
|
+
"value": "b",
|
|
500
|
+
"matches": true,
|
|
501
|
+
"translatable": true
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"pattern": "a|b",
|
|
505
|
+
"value": "c",
|
|
506
|
+
"matches": false,
|
|
507
|
+
"translatable": true
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
"pattern": "a.c",
|
|
511
|
+
"value": "abc",
|
|
512
|
+
"matches": true,
|
|
513
|
+
"translatable": true
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
"pattern": "a\\.c",
|
|
517
|
+
"value": "a.c",
|
|
518
|
+
"matches": true,
|
|
519
|
+
"translatable": true
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
"pattern": "\\i\\c*",
|
|
523
|
+
"value": "x",
|
|
524
|
+
"matches": false,
|
|
525
|
+
"translatable": false
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
"pattern": "[\\p{IsBasicLatin}-[abc]]+",
|
|
529
|
+
"value": "a",
|
|
530
|
+
"matches": false,
|
|
531
|
+
"translatable": false
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
"pattern": "\\p{IsNoSuchBlock}",
|
|
535
|
+
"value": "a",
|
|
536
|
+
"matches": false,
|
|
537
|
+
"translatable": false
|
|
538
|
+
}
|
|
539
|
+
],
|
|
540
|
+
"schema_wildcards": [
|
|
541
|
+
{
|
|
542
|
+
"constraint": "##any",
|
|
543
|
+
"process": "strict",
|
|
544
|
+
"not_namespace": null,
|
|
545
|
+
"not_qname": [],
|
|
546
|
+
"item_namespace": "local",
|
|
547
|
+
"item_qname": "{}x",
|
|
548
|
+
"defined": false,
|
|
549
|
+
"sibling_names": [],
|
|
550
|
+
"covers": true,
|
|
551
|
+
"exclusion": null
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
"constraint": "##any",
|
|
555
|
+
"process": "strict",
|
|
556
|
+
"not_namespace": null,
|
|
557
|
+
"not_qname": [],
|
|
558
|
+
"item_namespace": "tns",
|
|
559
|
+
"item_qname": "{}x",
|
|
560
|
+
"defined": false,
|
|
561
|
+
"sibling_names": [],
|
|
562
|
+
"covers": true,
|
|
563
|
+
"exclusion": null
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
"constraint": "##other",
|
|
567
|
+
"process": "strict",
|
|
568
|
+
"not_namespace": null,
|
|
569
|
+
"not_qname": [],
|
|
570
|
+
"item_namespace": "local",
|
|
571
|
+
"item_qname": "{}x",
|
|
572
|
+
"defined": false,
|
|
573
|
+
"sibling_names": [],
|
|
574
|
+
"covers": false,
|
|
575
|
+
"exclusion": null
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
"constraint": "##other",
|
|
579
|
+
"process": "strict",
|
|
580
|
+
"not_namespace": null,
|
|
581
|
+
"not_qname": [],
|
|
582
|
+
"item_namespace": "tns",
|
|
583
|
+
"item_qname": "{}x",
|
|
584
|
+
"defined": false,
|
|
585
|
+
"sibling_names": [],
|
|
586
|
+
"covers": false,
|
|
587
|
+
"exclusion": null
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
"constraint": "##other",
|
|
591
|
+
"process": "strict",
|
|
592
|
+
"not_namespace": null,
|
|
593
|
+
"not_qname": [],
|
|
594
|
+
"item_namespace": "urn:other",
|
|
595
|
+
"item_qname": "{}x",
|
|
596
|
+
"defined": false,
|
|
597
|
+
"sibling_names": [],
|
|
598
|
+
"covers": true,
|
|
599
|
+
"exclusion": null
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"constraint": "##local",
|
|
603
|
+
"process": "strict",
|
|
604
|
+
"not_namespace": null,
|
|
605
|
+
"not_qname": [],
|
|
606
|
+
"item_namespace": "local",
|
|
607
|
+
"item_qname": "{}x",
|
|
608
|
+
"defined": false,
|
|
609
|
+
"sibling_names": [],
|
|
610
|
+
"covers": true,
|
|
611
|
+
"exclusion": null
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
"constraint": "##local",
|
|
615
|
+
"process": "strict",
|
|
616
|
+
"not_namespace": null,
|
|
617
|
+
"not_qname": [],
|
|
618
|
+
"item_namespace": "urn:b",
|
|
619
|
+
"item_qname": "{}x",
|
|
620
|
+
"defined": false,
|
|
621
|
+
"sibling_names": [],
|
|
622
|
+
"covers": false,
|
|
623
|
+
"exclusion": null
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
"constraint": "##targetNamespace urn:b",
|
|
627
|
+
"process": "strict",
|
|
628
|
+
"not_namespace": null,
|
|
629
|
+
"not_qname": [],
|
|
630
|
+
"item_namespace": "tns",
|
|
631
|
+
"item_qname": "{}x",
|
|
632
|
+
"defined": false,
|
|
633
|
+
"sibling_names": [],
|
|
634
|
+
"covers": true,
|
|
635
|
+
"exclusion": null
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
"constraint": "##targetNamespace urn:b",
|
|
639
|
+
"process": "strict",
|
|
640
|
+
"not_namespace": null,
|
|
641
|
+
"not_qname": [],
|
|
642
|
+
"item_namespace": "local",
|
|
643
|
+
"item_qname": "{}x",
|
|
644
|
+
"defined": false,
|
|
645
|
+
"sibling_names": [],
|
|
646
|
+
"covers": false,
|
|
647
|
+
"exclusion": null
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
"constraint": "urn:a urn:b",
|
|
651
|
+
"process": "strict",
|
|
652
|
+
"not_namespace": null,
|
|
653
|
+
"not_qname": [],
|
|
654
|
+
"item_namespace": "urn:a",
|
|
655
|
+
"item_qname": "{}x",
|
|
656
|
+
"defined": false,
|
|
657
|
+
"sibling_names": [],
|
|
658
|
+
"covers": true,
|
|
659
|
+
"exclusion": null
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"constraint": "urn:a urn:b",
|
|
663
|
+
"process": "strict",
|
|
664
|
+
"not_namespace": null,
|
|
665
|
+
"not_qname": [],
|
|
666
|
+
"item_namespace": "urn:c",
|
|
667
|
+
"item_qname": "{}x",
|
|
668
|
+
"defined": false,
|
|
669
|
+
"sibling_names": [],
|
|
670
|
+
"covers": false,
|
|
671
|
+
"exclusion": null
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
"constraint": "urn:a",
|
|
675
|
+
"process": "lax",
|
|
676
|
+
"not_namespace": null,
|
|
677
|
+
"not_qname": [],
|
|
678
|
+
"item_namespace": "urn:a",
|
|
679
|
+
"item_qname": "{}x",
|
|
680
|
+
"defined": false,
|
|
681
|
+
"sibling_names": [],
|
|
682
|
+
"covers": true,
|
|
683
|
+
"exclusion": null
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"constraint": "urn:a",
|
|
687
|
+
"process": "skip",
|
|
688
|
+
"not_namespace": null,
|
|
689
|
+
"not_qname": [],
|
|
690
|
+
"item_namespace": "urn:a",
|
|
691
|
+
"item_qname": "{}x",
|
|
692
|
+
"defined": false,
|
|
693
|
+
"sibling_names": [],
|
|
694
|
+
"covers": true,
|
|
695
|
+
"exclusion": null
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
"constraint": "##any",
|
|
699
|
+
"process": "strict",
|
|
700
|
+
"not_namespace": null,
|
|
701
|
+
"not_qname": [
|
|
702
|
+
"x"
|
|
703
|
+
],
|
|
704
|
+
"item_namespace": "local",
|
|
705
|
+
"item_qname": "{}x",
|
|
706
|
+
"defined": false,
|
|
707
|
+
"sibling_names": [],
|
|
708
|
+
"covers": true,
|
|
709
|
+
"exclusion": "not_qname"
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
"constraint": "##any",
|
|
713
|
+
"process": "strict",
|
|
714
|
+
"not_namespace": null,
|
|
715
|
+
"not_qname": [
|
|
716
|
+
"x"
|
|
717
|
+
],
|
|
718
|
+
"item_namespace": "local",
|
|
719
|
+
"item_qname": "{}y",
|
|
720
|
+
"defined": false,
|
|
721
|
+
"sibling_names": [],
|
|
722
|
+
"covers": true,
|
|
723
|
+
"exclusion": null
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
"constraint": "##any",
|
|
727
|
+
"process": "lax",
|
|
728
|
+
"not_namespace": null,
|
|
729
|
+
"not_qname": [
|
|
730
|
+
"x"
|
|
731
|
+
],
|
|
732
|
+
"item_namespace": "local",
|
|
733
|
+
"item_qname": "{}x",
|
|
734
|
+
"defined": true,
|
|
735
|
+
"sibling_names": [],
|
|
736
|
+
"covers": true,
|
|
737
|
+
"exclusion": "not_qname"
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
"constraint": "##any",
|
|
741
|
+
"process": "skip",
|
|
742
|
+
"not_namespace": null,
|
|
743
|
+
"not_qname": [
|
|
744
|
+
"x"
|
|
745
|
+
],
|
|
746
|
+
"item_namespace": "local",
|
|
747
|
+
"item_qname": "{}x",
|
|
748
|
+
"defined": true,
|
|
749
|
+
"sibling_names": [],
|
|
750
|
+
"covers": true,
|
|
751
|
+
"exclusion": "not_qname"
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
"constraint": "##any",
|
|
755
|
+
"process": "strict",
|
|
756
|
+
"not_namespace": null,
|
|
757
|
+
"not_qname": [
|
|
758
|
+
"##defined"
|
|
759
|
+
],
|
|
760
|
+
"item_namespace": "local",
|
|
761
|
+
"item_qname": "{}x",
|
|
762
|
+
"defined": false,
|
|
763
|
+
"sibling_names": [],
|
|
764
|
+
"covers": true,
|
|
765
|
+
"exclusion": null
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
"constraint": "##any",
|
|
769
|
+
"process": "strict",
|
|
770
|
+
"not_namespace": null,
|
|
771
|
+
"not_qname": [
|
|
772
|
+
"##defined"
|
|
773
|
+
],
|
|
774
|
+
"item_namespace": "local",
|
|
775
|
+
"item_qname": "{}x",
|
|
776
|
+
"defined": true,
|
|
777
|
+
"sibling_names": [],
|
|
778
|
+
"covers": true,
|
|
779
|
+
"exclusion": "not_qname"
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
"constraint": "##any",
|
|
783
|
+
"process": "strict",
|
|
784
|
+
"not_namespace": null,
|
|
785
|
+
"not_qname": [
|
|
786
|
+
"##definedSibling"
|
|
787
|
+
],
|
|
788
|
+
"item_namespace": "local",
|
|
789
|
+
"item_qname": "{}x",
|
|
790
|
+
"defined": false,
|
|
791
|
+
"sibling_names": [
|
|
792
|
+
"{}y"
|
|
793
|
+
],
|
|
794
|
+
"covers": true,
|
|
795
|
+
"exclusion": null
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
"constraint": "##any",
|
|
799
|
+
"process": "strict",
|
|
800
|
+
"not_namespace": null,
|
|
801
|
+
"not_qname": [
|
|
802
|
+
"##definedSibling"
|
|
803
|
+
],
|
|
804
|
+
"item_namespace": "local",
|
|
805
|
+
"item_qname": "{}x",
|
|
806
|
+
"defined": false,
|
|
807
|
+
"sibling_names": [
|
|
808
|
+
"{}x"
|
|
809
|
+
],
|
|
810
|
+
"covers": true,
|
|
811
|
+
"exclusion": "not_qname"
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
"constraint": "urn:a",
|
|
815
|
+
"process": "strict",
|
|
816
|
+
"not_namespace": "urn:z",
|
|
817
|
+
"not_qname": [],
|
|
818
|
+
"item_namespace": "urn:a",
|
|
819
|
+
"item_qname": "{}x",
|
|
820
|
+
"defined": false,
|
|
821
|
+
"sibling_names": [],
|
|
822
|
+
"covers": true,
|
|
823
|
+
"exclusion": null
|
|
824
|
+
},
|
|
825
|
+
{
|
|
826
|
+
"constraint": "urn:a",
|
|
827
|
+
"process": "strict",
|
|
828
|
+
"not_namespace": "urn:z",
|
|
829
|
+
"not_qname": [],
|
|
830
|
+
"item_namespace": "urn:z",
|
|
831
|
+
"item_qname": "{}x",
|
|
832
|
+
"defined": false,
|
|
833
|
+
"sibling_names": [],
|
|
834
|
+
"covers": false,
|
|
835
|
+
"exclusion": "not_namespace"
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
"constraint": "urn:a",
|
|
839
|
+
"process": "lax",
|
|
840
|
+
"not_namespace": "urn:z",
|
|
841
|
+
"not_qname": [],
|
|
842
|
+
"item_namespace": "urn:z",
|
|
843
|
+
"item_qname": "{}x",
|
|
844
|
+
"defined": false,
|
|
845
|
+
"sibling_names": [],
|
|
846
|
+
"covers": false,
|
|
847
|
+
"exclusion": "not_namespace"
|
|
848
|
+
}
|
|
849
|
+
],
|
|
850
|
+
"entity_registry": [
|
|
851
|
+
{
|
|
852
|
+
"seed": {
|
|
853
|
+
"amp": "&"
|
|
854
|
+
},
|
|
855
|
+
"qname": "amp",
|
|
856
|
+
"qcp": 38,
|
|
857
|
+
"restore_entities": false,
|
|
858
|
+
"mode": "lenient",
|
|
859
|
+
"declared": true,
|
|
860
|
+
"codepoint": 38,
|
|
861
|
+
"names": [
|
|
862
|
+
"amp"
|
|
863
|
+
],
|
|
864
|
+
"primary": "amp",
|
|
865
|
+
"standard": true,
|
|
866
|
+
"restore": true
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
"seed": {
|
|
870
|
+
"NonBreakingSpace": " ",
|
|
871
|
+
"nbsp": " "
|
|
872
|
+
},
|
|
873
|
+
"qname": "nbsp",
|
|
874
|
+
"qcp": 160,
|
|
875
|
+
"restore_entities": true,
|
|
876
|
+
"mode": "lenient",
|
|
877
|
+
"declared": true,
|
|
878
|
+
"codepoint": 160,
|
|
879
|
+
"names": [
|
|
880
|
+
"NonBreakingSpace",
|
|
881
|
+
"nbsp"
|
|
882
|
+
],
|
|
883
|
+
"primary": "nbsp",
|
|
884
|
+
"standard": false,
|
|
885
|
+
"restore": true
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
"seed": {
|
|
889
|
+
"nbsp": " "
|
|
890
|
+
},
|
|
891
|
+
"qname": "nbsp",
|
|
892
|
+
"qcp": 160,
|
|
893
|
+
"restore_entities": false,
|
|
894
|
+
"mode": "lenient",
|
|
895
|
+
"declared": true,
|
|
896
|
+
"codepoint": 160,
|
|
897
|
+
"names": [
|
|
898
|
+
"nbsp"
|
|
899
|
+
],
|
|
900
|
+
"primary": "nbsp",
|
|
901
|
+
"standard": false,
|
|
902
|
+
"restore": false
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
"seed": {
|
|
906
|
+
"nbsp": " "
|
|
907
|
+
},
|
|
908
|
+
"qname": "nbsp",
|
|
909
|
+
"qcp": 160,
|
|
910
|
+
"restore_entities": true,
|
|
911
|
+
"mode": "strict",
|
|
912
|
+
"declared": true,
|
|
913
|
+
"codepoint": 160,
|
|
914
|
+
"names": [
|
|
915
|
+
"nbsp"
|
|
916
|
+
],
|
|
917
|
+
"primary": "nbsp",
|
|
918
|
+
"standard": false,
|
|
919
|
+
"restore": true
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
"seed": {
|
|
923
|
+
"AElig": "Æ"
|
|
924
|
+
},
|
|
925
|
+
"qname": "AElig",
|
|
926
|
+
"qcp": 198,
|
|
927
|
+
"restore_entities": true,
|
|
928
|
+
"mode": "lenient",
|
|
929
|
+
"declared": true,
|
|
930
|
+
"codepoint": 198,
|
|
931
|
+
"names": [
|
|
932
|
+
"AElig"
|
|
933
|
+
],
|
|
934
|
+
"primary": "AElig",
|
|
935
|
+
"standard": false,
|
|
936
|
+
"restore": true
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
"seed": {
|
|
940
|
+
"fjlig": "fj"
|
|
941
|
+
},
|
|
942
|
+
"qname": "fjlig",
|
|
943
|
+
"qcp": 102,
|
|
944
|
+
"restore_entities": true,
|
|
945
|
+
"mode": "lenient",
|
|
946
|
+
"declared": true,
|
|
947
|
+
"codepoint": 102,
|
|
948
|
+
"names": [
|
|
949
|
+
"fjlig"
|
|
950
|
+
],
|
|
951
|
+
"primary": "fjlig",
|
|
952
|
+
"standard": false,
|
|
953
|
+
"restore": true
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
"seed": {
|
|
957
|
+
"DotDot": " ⃜"
|
|
958
|
+
},
|
|
959
|
+
"qname": "DotDot",
|
|
960
|
+
"qcp": 32,
|
|
961
|
+
"restore_entities": true,
|
|
962
|
+
"mode": "lenient",
|
|
963
|
+
"declared": true,
|
|
964
|
+
"codepoint": 32,
|
|
965
|
+
"names": [
|
|
966
|
+
"DotDot"
|
|
967
|
+
],
|
|
968
|
+
"primary": "DotDot",
|
|
969
|
+
"standard": false,
|
|
970
|
+
"restore": true
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
"seed": {
|
|
974
|
+
"NotEqualTilde": "≂̸"
|
|
975
|
+
},
|
|
976
|
+
"qname": "NotEqualTilde",
|
|
977
|
+
"qcp": 8770,
|
|
978
|
+
"restore_entities": true,
|
|
979
|
+
"mode": "lenient",
|
|
980
|
+
"declared": true,
|
|
981
|
+
"codepoint": 8770,
|
|
982
|
+
"names": [
|
|
983
|
+
"NotEqualTilde"
|
|
984
|
+
],
|
|
985
|
+
"primary": "NotEqualTilde",
|
|
986
|
+
"standard": false,
|
|
987
|
+
"restore": true
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
"seed": {
|
|
991
|
+
"esc": "\\u00A0"
|
|
992
|
+
},
|
|
993
|
+
"qname": "esc",
|
|
994
|
+
"qcp": 160,
|
|
995
|
+
"restore_entities": true,
|
|
996
|
+
"mode": "lenient",
|
|
997
|
+
"declared": true,
|
|
998
|
+
"codepoint": 160,
|
|
999
|
+
"names": [
|
|
1000
|
+
"esc"
|
|
1001
|
+
],
|
|
1002
|
+
"primary": "esc",
|
|
1003
|
+
"standard": false,
|
|
1004
|
+
"restore": true
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
"seed": {
|
|
1008
|
+
"bad": ""
|
|
1009
|
+
},
|
|
1010
|
+
"qname": "bad",
|
|
1011
|
+
"qcp": 0,
|
|
1012
|
+
"restore_entities": true,
|
|
1013
|
+
"mode": "lenient",
|
|
1014
|
+
"declared": false,
|
|
1015
|
+
"codepoint": null,
|
|
1016
|
+
"names": [],
|
|
1017
|
+
"primary": null,
|
|
1018
|
+
"standard": false,
|
|
1019
|
+
"restore": false
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
"seed": {
|
|
1023
|
+
"nbsp": " "
|
|
1024
|
+
},
|
|
1025
|
+
"qname": "nope",
|
|
1026
|
+
"qcp": 9999,
|
|
1027
|
+
"restore_entities": true,
|
|
1028
|
+
"mode": "lenient",
|
|
1029
|
+
"declared": false,
|
|
1030
|
+
"codepoint": null,
|
|
1031
|
+
"names": [],
|
|
1032
|
+
"primary": null,
|
|
1033
|
+
"standard": false,
|
|
1034
|
+
"restore": false
|
|
1035
|
+
}
|
|
411
1036
|
]
|
|
412
1037
|
}
|
|
413
1038
|
}
|
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
|
|
@@ -30,6 +30,58 @@ module Moxml
|
|
|
30
30
|
# Standard XML predefined entities (XML spec §4.6)
|
|
31
31
|
STANDARD_CODEPOINTS = Set[0x26, 0x3C, 0x3E, 0x22, 0x27].freeze
|
|
32
32
|
|
|
33
|
+
# The entity-registry conformance dataset (#496): lookup and
|
|
34
|
+
# restoration answers as data, pinned BY the Ruby suite
|
|
35
|
+
# (spec/moxml/entity_registry_conformance_spec.rb) and exported
|
|
36
|
+
# for the Rust/TS runners. Row shape: [seed, qname, qcp,
|
|
37
|
+
# restore_entities, restoration_mode, declared, codepoint, names,
|
|
38
|
+
# primary, standard, restore]. Each row seeds a fresh :custom
|
|
39
|
+
# registry through the public provider path — so the seed values
|
|
40
|
+
# are LEXICAL forms (raw characters, multi-character sequences,
|
|
41
|
+
# "\\uXXXX" escapes), exercising parse_codepoint exactly as a
|
|
42
|
+
# custom provider does — then queries one name and one codepoint
|
|
43
|
+
# and pins every face answer:
|
|
44
|
+
#
|
|
45
|
+
# * declared?/codepoint_for_name on qname
|
|
46
|
+
# * names_for_codepoint/primary_name_for_codepoint on qcp
|
|
47
|
+
# * standard_entity?/should_restore? on qcp under the row's config
|
|
48
|
+
#
|
|
49
|
+
# The committed semantics the rows pin: a multi-character lexical
|
|
50
|
+
# (an entity naming a sequence, e.g. "fjlig" -> "fj") maps to its
|
|
51
|
+
# FIRST character's codepoint; an empty lexical is dropped; the
|
|
52
|
+
# reverse map keeps insertion order with the lowercase name
|
|
53
|
+
# preferred as primary (falling back to the first name); the five
|
|
54
|
+
# predefined entities restore regardless of config; every other
|
|
55
|
+
# known codepoint restores only with restore_entities on (the
|
|
56
|
+
# strict mode answers as lenient until DTD parsing exists); an
|
|
57
|
+
# unknown codepoint never restores.
|
|
58
|
+
ENTITY_CONFORMANCE_CASES = [
|
|
59
|
+
[{ "amp" => "&" }, "amp", 38, false, "lenient",
|
|
60
|
+
true, 38, ["amp"], "amp", true, true],
|
|
61
|
+
[{ "NonBreakingSpace" => "\u00A0", "nbsp" => "\u00A0" },
|
|
62
|
+
"nbsp", 160, true, "lenient",
|
|
63
|
+
true, 160, ["NonBreakingSpace", "nbsp"], "nbsp", false, true],
|
|
64
|
+
[{ "nbsp" => "\u00A0" }, "nbsp", 160, false, "lenient",
|
|
65
|
+
true, 160, ["nbsp"], "nbsp", false, false],
|
|
66
|
+
[{ "nbsp" => "\u00A0" }, "nbsp", 160, true, "strict",
|
|
67
|
+
true, 160, ["nbsp"], "nbsp", false, true],
|
|
68
|
+
[{ "AElig" => "Æ" }, "AElig", 198, true, "lenient",
|
|
69
|
+
true, 198, ["AElig"], "AElig", false, true],
|
|
70
|
+
[{ "fjlig" => "fj" }, "fjlig", 102, true, "lenient",
|
|
71
|
+
true, 102, ["fjlig"], "fjlig", false, true],
|
|
72
|
+
[{ "DotDot" => "\u0020\u20DC" }, "DotDot", 32, true, "lenient",
|
|
73
|
+
true, 32, ["DotDot"], "DotDot", false, true],
|
|
74
|
+
[{ "NotEqualTilde" => "≂̸" }, "NotEqualTilde", 8770, true,
|
|
75
|
+
"lenient",
|
|
76
|
+
true, 8770, ["NotEqualTilde"], "NotEqualTilde", false, true],
|
|
77
|
+
[{ "esc" => "\\u00A0" }, "esc", 160, true, "lenient",
|
|
78
|
+
true, 160, ["esc"], "esc", false, true],
|
|
79
|
+
[{ "bad" => "" }, "bad", 0, true, "lenient",
|
|
80
|
+
false, nil, [], nil, false, false],
|
|
81
|
+
[{ "nbsp" => "\u00A0" }, "nope", 9999, true, "lenient",
|
|
82
|
+
false, nil, [], nil, false, false],
|
|
83
|
+
].map(&:freeze).freeze
|
|
84
|
+
|
|
33
85
|
class << self
|
|
34
86
|
# Get the raw entity data from the bundled JSON source
|
|
35
87
|
# @return [Hash{String => String}] entity name to character mapping
|
data/lib/moxml/version.rb
CHANGED
|
@@ -78,17 +78,83 @@ module Moxml
|
|
|
78
78
|
nil
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
+
# The wildcard-face conformance dataset (#496): admission and
|
|
82
|
+
# negative-exclusion answers as data, pinned BY the Ruby suite
|
|
83
|
+
# (spec/moxml/wildcard_conformance_spec.rb) and exported for
|
|
84
|
+
# the Rust/TS runners. Row shape: [constraint, process,
|
|
85
|
+
# not_namespace, not_qname tokens, item_namespace, item_qname,
|
|
86
|
+
# defined, sibling_names, covers, exclusion]. Disallowed
|
|
87
|
+
# entries keep the pre-resolution token forms the constructor
|
|
88
|
+
# receives; item qnames are in the Clark form the face
|
|
89
|
+
# receives; item namespaces use the face's spellings
|
|
90
|
+
# ("local", "tns", or the URI).
|
|
91
|
+
WILDCARD_CASES = [
|
|
92
|
+
["##any", "strict", nil, [], "local", "{}x", false, [], true, nil],
|
|
93
|
+
["##any", "strict", nil, [], "tns", "{}x", false, [], true, nil],
|
|
94
|
+
["##other", "strict", nil, [], "local", "{}x", false, [], false, nil],
|
|
95
|
+
["##other", "strict", nil, [], "tns", "{}x", false, [], false, nil],
|
|
96
|
+
["##other", "strict", nil, [], "urn:other", "{}x", false, [], true, nil],
|
|
97
|
+
["##local", "strict", nil, [], "local", "{}x", false, [], true, nil],
|
|
98
|
+
["##local", "strict", nil, [], "urn:b", "{}x", false, [], false, nil],
|
|
99
|
+
["##targetNamespace urn:b", "strict", nil, [], "tns", "{}x", false, [],
|
|
100
|
+
true, nil],
|
|
101
|
+
["##targetNamespace urn:b", "strict", nil, [], "local", "{}x", false,
|
|
102
|
+
[], false, nil],
|
|
103
|
+
["urn:a urn:b", "strict", nil, [], "urn:a", "{}x", false, [], true,
|
|
104
|
+
nil],
|
|
105
|
+
["urn:a urn:b", "strict", nil, [], "urn:c", "{}x", false, [], false,
|
|
106
|
+
nil],
|
|
107
|
+
["urn:a", "lax", nil, [], "urn:a", "{}x", false, [], true, nil],
|
|
108
|
+
["urn:a", "skip", nil, [], "urn:a", "{}x", false, [], true, nil],
|
|
109
|
+
["##any", "strict", nil, ["x"], "local", "{}x", false, [], true,
|
|
110
|
+
"not_qname"],
|
|
111
|
+
["##any", "strict", nil, ["x"], "local", "{}y", false, [], true, nil],
|
|
112
|
+
["##any", "lax", nil, ["x"], "local", "{}x", true, [], true,
|
|
113
|
+
"not_qname"],
|
|
114
|
+
["##any", "skip", nil, ["x"], "local", "{}x", true, [], true,
|
|
115
|
+
"not_qname"],
|
|
116
|
+
["##any", "strict", nil, ["##defined"], "local", "{}x", false, [],
|
|
117
|
+
true, nil],
|
|
118
|
+
["##any", "strict", nil, ["##defined"], "local", "{}x", true, [],
|
|
119
|
+
true, "not_qname"],
|
|
120
|
+
["##any", "strict", nil, ["##definedSibling"], "local", "{}x", false,
|
|
121
|
+
["{}y"], true, nil],
|
|
122
|
+
["##any", "strict", nil, ["##definedSibling"], "local", "{}x", false,
|
|
123
|
+
["{}x"], true, "not_qname"],
|
|
124
|
+
["urn:a", "strict", "urn:z", [], "urn:a", "{}x", false, [], true,
|
|
125
|
+
nil],
|
|
126
|
+
["urn:a", "strict", "urn:z", [], "urn:z", "{}x", false, [], false,
|
|
127
|
+
"not_namespace"],
|
|
128
|
+
["urn:a", "lax", "urn:z", [], "urn:z", "{}x", false, [], false,
|
|
129
|
+
"not_namespace"],
|
|
130
|
+
].map(&:freeze).freeze
|
|
131
|
+
|
|
81
132
|
private
|
|
82
133
|
|
|
83
134
|
def namespace_constraint(value, not_namespace)
|
|
84
135
|
if not_namespace
|
|
85
|
-
[:not, not_namespace
|
|
136
|
+
[:not, namespace_entries(not_namespace)]
|
|
86
137
|
elsif value.nil? || value == "##any" || value == ""
|
|
87
138
|
[:any, []]
|
|
88
139
|
elsif value == "##other"
|
|
89
140
|
[:other, []]
|
|
90
141
|
else
|
|
91
|
-
[:list, value
|
|
142
|
+
[:list, namespace_entries(value)]
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Namespace entries carry one internal convention: the
|
|
147
|
+
# special tokens keep their string spellings (entry_covers?
|
|
148
|
+
# maps them to :tns/:local); real URIs become Symbols, the
|
|
149
|
+
# same shape covers? receives. A String entry would never
|
|
150
|
+
# equal a Symbol namespace — the comparison would silently
|
|
151
|
+
# under-report on every :list and :not wildcard.
|
|
152
|
+
def namespace_entries(value)
|
|
153
|
+
value.to_s.split(/\s+/).reject(&:empty?).map do |entry|
|
|
154
|
+
case entry
|
|
155
|
+
when "##targetNamespace", "##local" then entry
|
|
156
|
+
else entry.to_sym
|
|
157
|
+
end
|
|
92
158
|
end
|
|
93
159
|
end
|
|
94
160
|
|
|
@@ -131,7 +197,7 @@ module Moxml
|
|
|
131
197
|
:attribute_default, :elements,
|
|
132
198
|
:attributes, :contents, :version,
|
|
133
199
|
:element_patterns, :attribute_patterns,
|
|
134
|
-
:substitution_members)
|
|
200
|
+
:substitution_members, :self_contained)
|
|
135
201
|
|
|
136
202
|
# Resolves a QName token against an element's in-scope
|
|
137
203
|
# bindings. node.namespaces is adapter-divergent (some
|
|
@@ -189,6 +255,35 @@ module Moxml
|
|
|
189
255
|
nil
|
|
190
256
|
end
|
|
191
257
|
|
|
258
|
+
# The cross-language conformance dataset (#496): the
|
|
259
|
+
# translator's answers as data, pinned BY the Ruby suite
|
|
260
|
+
# (spec/moxml/xsd_regex_conformance_spec.rb) and exported to
|
|
261
|
+
# conformance/moxml-conformance.json for the Rust/TS runners.
|
|
262
|
+
# Each row: [pattern, value, matches, translatable].
|
|
263
|
+
CONFORMANCE_CASES = [
|
|
264
|
+
["\\p{IsBasicLatin}+", "abc", true, true],
|
|
265
|
+
["\\p{IsBasicLatin}+", "", false, true],
|
|
266
|
+
["\\P{IsLatin-1Supplement}", "a", true, true],
|
|
267
|
+
["\\P{IsLatin-1Supplement}", "é", false, true],
|
|
268
|
+
["\\p{IsGreek}", "α", true, true],
|
|
269
|
+
["\\p{IsGreek}", "a", false, true],
|
|
270
|
+
["\\p{L}", "a", true, true],
|
|
271
|
+
["\\p{L}", "1", false, true],
|
|
272
|
+
["\\p{Nd}{1,3}", "5", true, true],
|
|
273
|
+
["\\p{Nd}{1,3}", "abc", false, true],
|
|
274
|
+
["\\d{1,3}", "5", false, false],
|
|
275
|
+
["\\d{1,3}", "abc", false, false],
|
|
276
|
+
["[0-9]{1,3}", "42", true, true],
|
|
277
|
+
["[a-z]*", "", true, true],
|
|
278
|
+
["a|b", "b", true, true],
|
|
279
|
+
["a|b", "c", false, true],
|
|
280
|
+
["a.c", "abc", true, true],
|
|
281
|
+
["a\\.c", "a.c", true, true],
|
|
282
|
+
["\\i\\c*", "x", false, false],
|
|
283
|
+
["[\\p{IsBasicLatin}-[abc]]+", "a", false, false],
|
|
284
|
+
["\\p{IsNoSuchBlock}", "a", false, false],
|
|
285
|
+
].map(&:freeze).freeze
|
|
286
|
+
|
|
192
287
|
def scan(pattern)
|
|
193
288
|
out = +""
|
|
194
289
|
index = 0
|
|
@@ -243,7 +338,7 @@ module Moxml
|
|
|
243
338
|
# Index one schema document. Returns nil when the source
|
|
244
339
|
# cannot be indexed — the engine's answer then stands alone
|
|
245
340
|
# (today's behavior).
|
|
246
|
-
def index(schema_source, context)
|
|
341
|
+
def index(schema_source, context, self_contained: nil)
|
|
247
342
|
root = context.parse(schema_source).root
|
|
248
343
|
return nil unless root&.name == "schema"
|
|
249
344
|
|
|
@@ -251,7 +346,8 @@ module Moxml
|
|
|
251
346
|
root["targetNamespace"].to_s,
|
|
252
347
|
root["elementFormDefault"] == "qualified",
|
|
253
348
|
root["attributeFormDefault"] == "qualified",
|
|
254
|
-
{}, {}, {}, schema_version(root), {}, {}, {}
|
|
349
|
+
{}, {}, {}, schema_version(root), {}, {}, {},
|
|
350
|
+
self_contained.nil? ? composition_free?(root) : self_contained
|
|
255
351
|
)
|
|
256
352
|
child_elements(root).each do |decl|
|
|
257
353
|
case decl.name
|
|
@@ -265,6 +361,24 @@ module Moxml
|
|
|
265
361
|
nil
|
|
266
362
|
end
|
|
267
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
|
+
|
|
268
382
|
# The effective schema version declared at the root
|
|
269
383
|
# (#460 item 2): vc:minVersion="1.1" on <xs:schema> scopes
|
|
270
384
|
# the document to 1.1 semantics; anything else reports
|
|
@@ -511,12 +625,18 @@ module Moxml
|
|
|
511
625
|
model = index.contents[root_qname]
|
|
512
626
|
findings = []
|
|
513
627
|
findings << nil_finding(root, declaration) if declaration
|
|
514
|
-
|
|
515
|
-
|
|
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
|
|
516
633
|
child_elements(root).each do |child|
|
|
517
634
|
findings.concat(child_findings(child, model, index))
|
|
518
635
|
end
|
|
519
636
|
end
|
|
637
|
+
if index.self_contained
|
|
638
|
+
findings.concat(attribute_findings(root, model, index))
|
|
639
|
+
end
|
|
520
640
|
findings.compact
|
|
521
641
|
end
|
|
522
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/lib/moxml.rb
CHANGED
|
@@ -101,7 +101,7 @@ module Moxml
|
|
|
101
101
|
autoload :Adapter, "moxml/adapter"
|
|
102
102
|
autoload :XPath, "moxml/xpath"
|
|
103
103
|
autoload :SAX, "moxml/sax"
|
|
104
|
-
autoload :Signature, "moxml/signature"
|
|
104
|
+
autoload :Signature, "moxml/signature" unless RUBY_ENGINE == "opal"
|
|
105
105
|
autoload :C14n, "moxml/c14n"
|
|
106
106
|
autoload :Reference, "moxml/reference"
|
|
107
107
|
autoload :XSLT, "moxml/xslt"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Processing model §Entities (normative): pinned here.
|
|
4
|
+
|
|
5
|
+
require "spec_helper"
|
|
6
|
+
|
|
7
|
+
# The entity-registry conformance dataset (#496): lookup and
|
|
8
|
+
# restoration answers AS DATA, pinned by the Ruby suite and exported
|
|
9
|
+
# for the Rust/TS runners. A row failing here breaks the
|
|
10
|
+
# cross-language contract. Rows seed a fresh :custom registry through
|
|
11
|
+
# the public provider path — seed values are lexical forms — then pin
|
|
12
|
+
# every face answer for one name and one codepoint query.
|
|
13
|
+
RSpec.describe "entity-registry conformance dataset" do
|
|
14
|
+
it "carries the dataset" do
|
|
15
|
+
expect(Moxml::EntityRegistry::ENTITY_CONFORMANCE_CASES.size).to be >= 10
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "answers every row exactly as the dataset expects" do
|
|
19
|
+
Moxml::EntityRegistry::ENTITY_CONFORMANCE_CASES.each do |row|
|
|
20
|
+
seed, qname, qcp, restore_entities, restoration_mode, declared,
|
|
21
|
+
codepoint, names, primary, standard, restore = row
|
|
22
|
+
registry = Moxml::EntityRegistry.new(
|
|
23
|
+
mode: :custom,
|
|
24
|
+
entity_provider: -> { seed },
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
label = "seed #{seed.inspect}, qname #{qname.inspect}, qcp #{qcp}"
|
|
28
|
+
|
|
29
|
+
expect(registry.declared?(qname)).to eql(declared),
|
|
30
|
+
"declared?(#{qname.inspect}) [#{label}]"
|
|
31
|
+
expect(registry.codepoint_for_name(qname)).to eql(codepoint),
|
|
32
|
+
"codepoint_for_name(" \
|
|
33
|
+
"#{qname.inspect}) " \
|
|
34
|
+
"[#{label}]"
|
|
35
|
+
expect(registry.names_for_codepoint(qcp)).to eql(names),
|
|
36
|
+
"names_for_codepoint(" \
|
|
37
|
+
"#{qcp}) [#{label}]"
|
|
38
|
+
expect(registry.primary_name_for_codepoint(qcp)).to eql(primary),
|
|
39
|
+
"primary_name_" \
|
|
40
|
+
"for_codepoint(" \
|
|
41
|
+
"#{qcp}) [#{label}]"
|
|
42
|
+
expect(registry.standard_entity?(qcp)).to eql(standard),
|
|
43
|
+
"standard_entity?(#{qcp}) " \
|
|
44
|
+
"[#{label}]"
|
|
45
|
+
config = Moxml::Config.new
|
|
46
|
+
config.restore_entities = restore_entities
|
|
47
|
+
config.entity_restoration_mode = restoration_mode.to_sym
|
|
48
|
+
expect(registry.should_restore?(qcp, config: config)).to eql(restore),
|
|
49
|
+
"should_restore?(" \
|
|
50
|
+
"#{qcp}) " \
|
|
51
|
+
"[#{label}]"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "open3"
|
|
5
|
+
require "rbconfig"
|
|
6
|
+
require "tempfile"
|
|
7
|
+
require "opal"
|
|
8
|
+
|
|
9
|
+
RSpec.describe "Signature autoload boundary", :native_fs do
|
|
10
|
+
let(:lib) { File.expand_path("../../lib", __dir__) }
|
|
11
|
+
|
|
12
|
+
it "keeps the native signature module lazy and usable on Ruby" do
|
|
13
|
+
source = <<~RUBY_CODE
|
|
14
|
+
require "moxml"
|
|
15
|
+
abort "signature was loaded eagerly" if $LOADED_FEATURES.any? { |path| path.end_with?("moxml/signature.rb") }
|
|
16
|
+
abort "signature autoload missing" unless Moxml.autoload?(:Signature) == "moxml/signature"
|
|
17
|
+
abort "signature module unavailable" unless Moxml::Signature::DSIG_NS == "http://www.w3.org/2000/09/xmldsig#"
|
|
18
|
+
abort "OpenSSL unavailable" unless defined?(OpenSSL::PKey::RSA)
|
|
19
|
+
puts "native signature available"
|
|
20
|
+
RUBY_CODE
|
|
21
|
+
output, error, status = Open3.capture3(RbConfig.ruby, "-I", lib, "-e", source)
|
|
22
|
+
expect(status.success?).to be(true), error
|
|
23
|
+
expect(output).to include("native signature available")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "does not compile the native OpenSSL dependency into Opal" do
|
|
27
|
+
# Compile the actual entrypoint declaration. This isolates the optional
|
|
28
|
+
# signature boundary from the other modules loaded by the Opal boot file.
|
|
29
|
+
declaration = File.readlines(File.join(lib, "moxml.rb"))
|
|
30
|
+
.find { |line| line.include?('autoload :Signature, "moxml/signature"') }
|
|
31
|
+
expect(declaration).not_to be_nil
|
|
32
|
+
|
|
33
|
+
builder = Opal::Builder.new
|
|
34
|
+
builder.append_paths(lib)
|
|
35
|
+
builder.build("opal")
|
|
36
|
+
builder.build_str(<<~RUBY_CODE, "signature-autoload-boundary")
|
|
37
|
+
module Moxml
|
|
38
|
+
#{declaration}
|
|
39
|
+
end
|
|
40
|
+
raise "native Signature loaded under Opal" if Moxml.const_defined?(:Signature, false)
|
|
41
|
+
puts "Opal signature boundary passed"
|
|
42
|
+
RUBY_CODE
|
|
43
|
+
|
|
44
|
+
Tempfile.create(["moxml-signature-boundary", ".js"]) do |file|
|
|
45
|
+
file.write(builder.to_s)
|
|
46
|
+
file.flush
|
|
47
|
+
output, error, status = Open3.capture3("node", file.path)
|
|
48
|
+
expect(status.success?).to be(true), error
|
|
49
|
+
expect(output).to include("Opal signature boundary passed")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Processing model §Validation (normative): pinned here.
|
|
4
|
+
|
|
5
|
+
require "spec_helper"
|
|
6
|
+
|
|
7
|
+
# The wildcard-face conformance dataset (#496): admission (covers?)
|
|
8
|
+
# and negative-exclusion answers AS DATA, pinned by the Ruby suite
|
|
9
|
+
# and exported for the Rust/TS runners. A row failing here breaks the
|
|
10
|
+
# cross-language contract. Rows drive the real Wildcard through its
|
|
11
|
+
# public constructor — disallowed entries in their pre-resolution
|
|
12
|
+
# token form, item qnames in the Clark form the face receives.
|
|
13
|
+
RSpec.describe "wildcard-face conformance dataset" do
|
|
14
|
+
it "carries the dataset" do
|
|
15
|
+
expect(Moxml::XSD::SchemaRules::Wildcard::WILDCARD_CASES.size).to be >= 20
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "answers every row exactly as the dataset expects" do
|
|
19
|
+
Moxml::XSD::SchemaRules::Wildcard::WILDCARD_CASES.each do |row|
|
|
20
|
+
constraint, process, not_namespace, not_qname, item_ns, item_qname,
|
|
21
|
+
defined, sibling_names, covers, exclusion = row
|
|
22
|
+
wildcard = Moxml::XSD::SchemaRules::Wildcard.new(
|
|
23
|
+
constraint, process,
|
|
24
|
+
not_namespace: not_namespace, not_qname: not_qname.join(" "),
|
|
25
|
+
element: nil
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
covers_answer = wildcard.covers?(item_ns.to_sym)
|
|
29
|
+
expect(covers_answer).to eql(covers),
|
|
30
|
+
"covers?(#{item_ns.inspect}) under " \
|
|
31
|
+
"#{constraint.inspect}: got " \
|
|
32
|
+
"#{covers_answer.inspect}, dataset expects " \
|
|
33
|
+
"#{covers.inspect}"
|
|
34
|
+
|
|
35
|
+
exclusion_answer = wildcard.negative_exclusion(
|
|
36
|
+
item_qname, item_ns.to_sym,
|
|
37
|
+
defined: defined, sibling_names: sibling_names
|
|
38
|
+
)
|
|
39
|
+
expected_exclusion = exclusion&.to_sym
|
|
40
|
+
expect(exclusion_answer).to eql(expected_exclusion),
|
|
41
|
+
"negative_exclusion(#{item_qname.inspect}, " \
|
|
42
|
+
"#{item_ns.inspect}) under " \
|
|
43
|
+
"#{constraint.inspect}: got " \
|
|
44
|
+
"#{exclusion_answer.inspect}, dataset expects " \
|
|
45
|
+
"#{expected_exclusion.inspect}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Processing model §Validation (normative): pinned here.
|
|
4
|
+
|
|
5
|
+
require "spec_helper"
|
|
6
|
+
|
|
7
|
+
# The regex-translator conformance dataset (#496): the translator's
|
|
8
|
+
# answers AS DATA — translatable-or-not, and what the translated
|
|
9
|
+
# regex does to sample values — pinned by the Ruby suite and exported
|
|
10
|
+
# for the Rust/TS runners. A row failing here breaks the
|
|
11
|
+
# cross-language contract.
|
|
12
|
+
RSpec.describe "XSD-regex translator conformance dataset" do
|
|
13
|
+
let(:translator) { Moxml::XSD::SchemaRules::XsdRegex }
|
|
14
|
+
|
|
15
|
+
it "carries the dataset" do
|
|
16
|
+
expect(translator::CONFORMANCE_CASES.size).to be >= 20
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "answers every row exactly as the dataset expects" do
|
|
20
|
+
translator::CONFORMANCE_CASES.each do |pattern, value, matches, translatable|
|
|
21
|
+
regex = translator.translate(pattern)
|
|
22
|
+
if translatable
|
|
23
|
+
expect(regex).not_to be_nil,
|
|
24
|
+
"#{pattern.inspect}: dataset says translatable, got nil"
|
|
25
|
+
answer = regex.match?(value)
|
|
26
|
+
expect(answer).to eql(matches),
|
|
27
|
+
"#{pattern.inspect} on #{value.inspect}: got " \
|
|
28
|
+
"#{answer.inspect}, dataset expects #{matches.inspect}"
|
|
29
|
+
else
|
|
30
|
+
expect(regex).to be_nil,
|
|
31
|
+
"#{pattern.inspect}: dataset says NOT translatable, " \
|
|
32
|
+
"got #{regex.inspect}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
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
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: moxml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.177
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -557,6 +557,7 @@ files:
|
|
|
557
557
|
- spec/moxml/element_spec.rb
|
|
558
558
|
- spec/moxml/entity_preservation_spec.rb
|
|
559
559
|
- spec/moxml/entity_reference_spec.rb
|
|
560
|
+
- spec/moxml/entity_registry_conformance_spec.rb
|
|
560
561
|
- spec/moxml/entity_registry_spec.rb
|
|
561
562
|
- spec/moxml/entity_spec.rb
|
|
562
563
|
- spec/moxml/error_spec.rb
|
|
@@ -606,11 +607,13 @@ files:
|
|
|
606
607
|
- spec/moxml/signature/key_extractor_spec.rb
|
|
607
608
|
- spec/moxml/signature/model_spec.rb
|
|
608
609
|
- spec/moxml/signature/round_trip_spec.rb
|
|
610
|
+
- spec/moxml/signature_autoload_spec.rb
|
|
609
611
|
- spec/moxml/struct_plan_spec.rb
|
|
610
612
|
- spec/moxml/struct_plan_typed_spec.rb
|
|
611
613
|
- spec/moxml/text_spec.rb
|
|
612
614
|
- spec/moxml/to_html_spec.rb
|
|
613
615
|
- spec/moxml/version_spec.rb
|
|
616
|
+
- spec/moxml/wildcard_conformance_spec.rb
|
|
614
617
|
- spec/moxml/xhtml_output_spec.rb
|
|
615
618
|
- spec/moxml/xml_emitter_spec.rb
|
|
616
619
|
- spec/moxml/xml_utils/.gitkeep
|
|
@@ -643,6 +646,7 @@ files:
|
|
|
643
646
|
- spec/moxml/xsd_engine_meta_spec.rb
|
|
644
647
|
- spec/moxml/xsd_error_contract_spec.rb
|
|
645
648
|
- spec/moxml/xsd_handle_mismatch_spec.rb
|
|
649
|
+
- spec/moxml/xsd_regex_conformance_spec.rb
|
|
646
650
|
- spec/moxml/xsd_regex_spec.rb
|
|
647
651
|
- spec/moxml/xsd_release_spec.rb
|
|
648
652
|
- spec/moxml/xsd_set_spec.rb
|