-
Notifications
You must be signed in to change notification settings - Fork 0
/
pmf.html
3106 lines (2635 loc) · 128 KB
/
pmf.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>PMFed</title>
<meta name="generator" content="Amaya, see http://www.w3.org/Amaya/" />
<link href="css/prism.css" rel="stylesheet" />
<style>
pre[class*="language-"] {
font-size: 12px;
font-style: normal;
font-family: monospace;
background-color: #ffffff;
}
span.code {
font-size: 10pt;
color: black;
}
span.code_comment {
font-size: 10pt;
color: green;
}
</style>
</head>
<body>
<script src="js/prism.js"></script>
<script src="js/prism_keep_tag.js"></script>
<h1 style="text-align:center;margin-left:auto;margin-right:auto;">"XML & JSON" Editor PMFed</h1>
<h2>Table of Contents</h2>
<div class="toc">
<ul>
<li><a href="#L30">Introduction</a>
<ul>
<li><a href="#L1874">What is PMFed ?</a></li>
</ul>
</li>
<li><a href="#L149">Tutorial</a>
<ul>
<li><a href="#L1987">PMFed for XML</a>
<ul>
<li><a href="#L1989">Classes Generation / XSD Schema Import</a>
<ul>
<li><a href="#L4145">XSD schema structure</a></li>
<li><a href="#L1999">Restrictions on the schemas</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#L2212">PMFed for JSON</a>
<ul>
<li><a href="#L2214">Classes Generation / JSON Schema Import</a>
<ul>
<li><a href="#L4444">JSON schema structure</a></li>
<li><a href="#L2258">Restrictions of JSON Schemas</a></li>
<li><a href="#L2274">"anyOf" tag</a></li>
<li><a href="#L2275">"oneOf" tag</a></li>
<li><a href="#L2276">"allOf" tag</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><a href="#L2439">Advanced Usage</a>
<ul>
<li><a href="#L2589">Mapping of Simple Type to Formular Widgets</a>
<ul>
<li><a href="#L1093">JSON Simple Types Mapping</a></li>
<li><a href="#L1307">XSD Simple Types Mapping</a></li>
</ul>
</li>
<li><a href="#L25891">Customization</a>
<ul>
<li><a href="#L2711">TreeView Customization</a>
<ul>
<li><a href="#L1923">Tree item icons</a></li>
<li><a href="#L1939">Tree item labels</a></li>
<li><a href="#L1955">Forbidding items of some classes to appears in the tree </a></li>
<li><a href="#L1954">Forbidding items of some classes to be interactively created in the tree </a></li>
<li><a href="#L1956">Forbidding items of some classes to be interactively deleted in the tree</a></li>
<li><a href="#L1957">Adding custom actions from the context menu</a></li>
</ul>
</li>
<li><a href="#L2720">Formulars Customization</a>
<ul>
<li><a href="#L20313">JSON Simple Types</a></li>
<li><a href="#L13071">XSD Simple Types</a></li>
<li><a href="#L2561">Complex Types in formulars</a></li>
<li><a href="#L2632">Extra formular widgets</a></li>
<li><a href="#L2786">Customization of formulars: custom attributes</a></li>
<li><a href="#L2787">Customization of formulars: title banner</a></li>
<li><a href="#L2814">Customization of formulars: help banner</a></li>
<li><a href="#L2815">Customization of formulars: notebook</a></li>
</ul>
</li>
<li><a href="#L272011">Customization of items as last leaves of a tree (1)</a></li>
<li><a href="#L13786">Customization of items as last leaves of a tree (2)</a></li>
<li><a href="#L13787">Customization of items as last leaves of a tree (3)</a></li>
<li><a href="#L10917">Customization of formulars: UI formulars</a></li>
<li><a href="#L2782">Customization of References</a></li>
<li><a href="#L2811">Choice of "selectable" objects for a reference</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#L2839">Appendix</a>
<ul>
<li><a href="#L2441">PMF Framework Built-In classes</a></li>
<li><a href="#L957">Observers</a></li>
<li><a href="#L28391">References declaration in XSDs</a></li>
<li><a href="#L3047">References declaration in JSON Schemas</a></li>
<li><a href="#L3048">File Splitting</a></li>
<li><a href="#L3049">Comments in XML</a></li>
</ul>
</li>
<li><a href="#L3839">Requirement / Dependencies</a>
<ul>
<li><a href="#L24117">Requirement </a></li>
<li><a href="#L24123">Dependencies</a></li>
</ul>
</li>
<li><a href="#L3551">FAQ</a>
<ul>
<li><a href="#L3553">The application at startup tries to load a file which does not follow the model
specified</a></li>
<li><a href="#L3575">XSD/JSON validation does not work</a></li>
<li><a href="#L3585">The tree view display the tree items with strange labels</a></li>
<li><a href="#L3589">From the logger validation outout, click on the error msg does not jump to the item in the
tree</a></li>
</ul>
</li>
</ul>
</div>
<h2 id="L30">Introduction</h2>
<h3 id="L1874">What is PMFed ?</h3>
<p><strong>PMFed is a graphical tree-formular editor application for XML or JSON, written in Python.</strong></p>
<p>It can read, edit and save any model which has been generated by the PMFed utility <strong>pmfgen</strong>.
This utility generates from a <strong>XSD</strong> or <strong>JSON Schema</strong> all necessary python classes defining a model.</p>
<p>Moreover, a developer or an attentive user can edit the generated classes for fine tuning.</p>
<p>The main features of <strong>PMFed</strong> are:</p>
<ul>
<li><strong>model based</strong>: works for every (not <span style="color:#ff0000">**too**</span> complicated) XSD or
JSON schema.</li>
<li>model classes are <strong>generated</strong> from the schema.</li>
<li><strong>intelligent tree</strong>: creation of new children based on the <strong>restrictions specified in the schema</strong>
(choice, minOccurs/maxOccurs).</li>
<li><strong>formulars</strong> are <span style="color:#ff0000">"real" formulars</span> for user friendly editing (not just strings to edit like in so many others apps)</li>
<li><strong>formulars are automatically derived from the model</strong>: a formular contains all the widgets
necessary to edit all the attributes of an element, and each widget in a formular is dedicated to the type of the
underlying attribute type. (SpinBox for integers types, ComboBox for enums etc.) and follow the <strong>possible
restrictions</strong> on the simple types specified in the schema (pattern, min, max, etc...).</li>
<li><strong>formulars</strong> can also be defined with <strong>Qt ui files</strong>.</li>
<li><strong>XSD/JSON schema validation on the "fly" during editing</strong> (and jump to location on validation error
msg click).</li>
<li><strong>support for "comments" in XML (see in Appendix)</strong>.</li>
<li><strong>support for "references" in XML models (unidirectional or bi-directional)</strong> through special
notations in the XSD schema (see in Appendix).</li>
<li><strong>support for "references" in JSON models (unidirectional or bi-directional)</strong> through special
notations in the JSON schema (see in Appendix).</li>
<li><strong>fully configurable</strong> through customizable generated python classes (see examples later).</li>
<li><strong><span style="color:#ff0000">support for file splitting</span></strong> (see in Appendix).</li>
</ul>
<p>More specifically, for users, the <strong>PMFed</strong> (<strong>PySide</strong> based) application allows to:</p>
<ul>
<li>open/read/save XML/JSON files compliant with the XSD/JSON schema (python module given in argument to the
application).</li>
<li>edit the tree (add/delete children, cut/copy/paste).</li>
<li>edit the items properties through formulars/widgets.</li>
<li>full undo-redo.</li>
<li>rich set of controls in formular (for every XSD simple type or JSON simple type).</li>
</ul>
<p><strong>How does it work?</strong></p>
<p>Given a schema (XSD or JSON), a bunch of classes corresponding to the complex types defined in the schema is created
in a python module (with the command line tool <strong>pmfgen.py</strong> furnished with the application).</p>
<p>Moreover, for each class generated in the module, a super class is also created (in its own python module), allowing
complete control over the generated classes. Finally, a framework is furnished, which is completely user model
agnostic. The framework implements a super class where the basic functionalities of the generated classes are
implemented. The <strong>PMFed</strong> application simply relies on this framework (and the generated classes), and
thus allows the tree-formular editor to work out of the box. The framework furnishes also a treeview, a formular view
and a logger view (with document validation) for the <strong>PMFed</strong> application.</p>
<p>Because the user will certainly want it, great care has be done so that the user can <strong>customize</strong> the
<strong>tree-formular application</strong> to fit its own needs:</p>
<ul>
<li>formulars are easily custumizable</li>
<li>tree view is easily customizable</li>
</ul>
<p><strong>In short, everything is customizable in a easy way</strong> (hopefully!)</p>
<h2 id="L149">Tutorial</h2>
<p>This tutorial presents how to start with PMFed.</p>
<p>After having installed the python code in a folder of your choice, set the environment variable
<code><strong>PMF_MODELS</strong></code> to any folder on the file system of your choice.
This simply defines the path where the models will be search in.</p>
<p>Starting the PMFed application is as follow:</p>
<pre><span style="font-size: 10pt">> python PMFed.py <model></span></pre>
<p>where the <strong><model></strong> refers to a folder inside the PMF_MODELS "root" folder.
But of what exactly consists the model?</p>
</p>
<p>The user has written a XSD schema or a JSON Schema. This is his first "model", and for simplicity we assume he has
named his model "<code>mymodel</code>": the XSD file is <code>mymodel.xsd</code> (or <code>mymodel.json</code>). Create
the folder <code>mymodel</code> under <code><strong>PMF_MODELS</strong></code>, and put the schema file in the folder
<code>mymodel</code>.</p>
<p>First step is to "import" the schema, i.e. to generate python classes for this model. This is done with the utility
<code>pmfgen.py</code>.</p>
<p><code>cd</code> to folder <code>mymodel</code>, and from the command line, type:</p>
<pre><span style="font-size: 10pt">> python pmfgen.py -t xsd -d html -o mymodel.py mymodel.xsd</span></pre>
<p>or</p>
<pre><span style="font-size: 10pt">> python pmfgen.py -t json -d html -o mymodel.py mymodel.json</span></pre>
<p>A python file <code><strong>mymodel.py</strong></code> is created as well as several other files.
<p>You should have in the file system:</p>
<pre><span style="font-size: 10pt">mymodel
+--- mymodel.xsd
+--- mymodel.py
customclasses
+--- class1.py
class2.py
...
html
+--- class1.html
class2.html
...</span></pre>
<p>Create per hand the folders <code>"icons"</code> and <code>"forms"</code> under the folder <code>mymodel</code>:</p>
<ul>
<li>under the folder <code>"icons"</code>, you can put icons files named after the classes names found in the model
(optional).</li>
<li>under the folder <code>"forms"</code>, you can put Qt ui files named after the classes names found in the model
(optional).</li>
</ul>
<pre><span style="font-size: 10pt">mymodel
+--- mymodel.xsd
+--- mymodel.py
customclasses
+--- class1.py
class2.py
...
html
+--- class1.html
class2.html
...
icons
+--- class1.png
class2.png
...
forms
+--- class1.ui
class2.ui
...</span></pre>
<p>You are ready to start the PMFed application: type the from the shell:</p>
<pre><span style="font-size: 10pt">> python PMFed.py mymodel</span></pre>
<p>The application should start-up. Congratulations. You can create, load and save files in the application and edit
them.</p>
<h3 id="L1987">PMFed for XML</h3>
<h4 id="L1989">Classes Generation / XSD Schema Import</h4>
<p>The <strong>pmfgen.py</strong> importer generates classes based on the XSD schema:</p>
<pre><span style="font-size: 10pt">> python pmfgen.py -t xsd -o mymodel.py [-d html] mymodel.xsd</span></pre>
<p>It generates the "main" python module <code>mymodel.py</code> and two folders: folder <code>"customclasses"</code>
containing a bunch of python modules for super classes for all the classes (complex types) defined in the model; folder
<code>"html_help"</code> containing html files (1 for each class) destined for the html help (if option <code>-d html</code>
was given). The user should create the (optional) folders <code>"icons"</code> and <code>"forms"</code>, where the
icons for the tree icons for each class are specified, and where the user custom formulars (qt ui files) can be
placed.</p>
<p>The "main" python module should never be edited. The super classes modules can be edited by hand, as well as the
html files.</p>
<p>On a second run, the python module <code>mymodel.py</code> is overwritten, but the folders for super classes and
html help files are not: new folders are created : <code>"customclasses_new"</code> and <code>"html_help_new"</code>. It is
the responsability of the user to merge them with the already edited files inside the <code>"customclasses"</code> and
<code>"html_help"</code> folders when the user has updated its xsd schema.</p>
<h5 id="L4145">XSD schema structure</h5>
<p>The user is invited to explore the examples of XSDs to see which kind of XSDs syntax/structure is understood by the
importer. A large set of the XSD schema syntax is supported. More precisely, because the importer generates classes
from the complex types specified in the XSD, the following XSD structure is required:</p>
<ul>
<li>complex types are specified within the tags <code><xs:complexType></code> and
<code></xs:complexType></code>.</li>
<li>inside a complex type, no other complex type can be defined (but other complex types can -of course- be used),
i.e. all complex types are defined in a "flat" list under the <code><xs:schema></code> tag.</li>
</ul>
<p>Note: As special feature, the importer can generate classes where objects owns "references" (pointers) -as in
defined in UML diagrams- on others objects. This is performed through the use of <strong>special tags</strong> in the
XSDs (see in appendix).</p>
<h5 id="L1999">Restrictions on the schemas</h5>
<ul>
<li>Inside a <code><strong><xs:choice></strong></code>, only complex types are allowed (no simple types or
mixed simple types/complex types)</li>
<li>Data Type not supported
<ul>
<li>anyURI</li>
<li>hexBinary</li>
<li>base64Binary</li>
<li>NOTATION</li>
</ul>
</li>
<li>String data types not supported
<ul>
<li>ENTITIES</li>
<li>ENTITY</li>
<li>language</li>
<li>Name</li>
<li>NCName</li>
<li>NMTKEN</li>
<li>NMTOKENS</li>
<li>normalizedString</li>
<li>QName</li>
<li>token</li>
<li>IDREFS</li>
</ul>
</li>
<li>Tag not supported
<ul>
<li>annotation</li>
<li>any</li>
<li>anyAttribute</li>
<li>appinfo</li>
<li>documentation</li>
<li>field</li>
<li>import</li>
<li>include</li>
<li>key</li>
<li>keyref</li>
<li>notation</li>
<li>redefine</li>
<li>substitution</li>
<li>selector</li>
<li>union</li>
<li>unique</li>
</ul>
</li>
<li>Restrictions not supported
<ul>
<li>whiteSpace</li>
<li>totalDigits</li>
</ul>
</li>
<li>Misc not supported
<ul>
<li>complexType "mixed"</li>
</ul>
</li>
</ul>
<p>This seems to be at first sight a long list. But infact none of these XSD specifications tags are needed to define a
full featured model.</p>
<h3 id="L2212">PMFed for JSON</h3>
<h4 id="L2214">Classes Generation / JSON Schema Import</h4>
<p>The <strong>pmfgen.py</strong> importer generates classes based on JSON schemas:</p>
<pre><span style="font-size: 10pt">> python pmfgen.py -t json -o <python_module>.py [-d html] <json schema>.xsd</span></pre>
<p>It generates the "main" python module <code><python_module>.py</code> and two folders: folder
<code>"customclasses"</code> containing a bunch of python modules for super classes for all the classes (complex types)
defined in the model; folder <code>"html_help"</code> containing html files (1 for each class) destined for the html help
(if option <code>-d html</code> was given). The user should create the (optional) folders <code>"icons"</code> and
<code>"forms"</code>, where the icons for the tree icons for each class are specified, and where the user custom
formulars (qt ui files) can be placed.</p>
<p>The "main" python module should never be edited. The super classes modules can be edited by hand, as well as the
html files.</p>
<p>On a second run, the python module <code><python_module>.py</code> is overwritten, but the folders for super
classes and html help files are not: new folders are created : <code>"customclasses_new"</code> and
<code>"html_help_new"</code>. It is the responsability of the user to merge them with the already edited files inside the
<code>"customclasses"</code> and <code>"html_help"</code> folders when the user has updated its json schema.</p>
<h5 id="L4444">JSON schema structure</h5>
<p>The user is invited to explore the examples of JSON Schemas to see which kind of JSON syntax/structure is understood
by the importer. A large set of the JSON Schema syntax is supported. </p>
<p>Similarly to XSD schemas, the preferred way to define complex types is by defining them as a flat list of complex
types, in the section "<strong>definitions</strong>" of the schema. But the importer also understands schemas where the
complex types are defined "inline", i.e. inside other complex types.</p>
<p>Note: As special feature, the importer can generate classes where objects owns "references" (pointers) -as in
defined in UML diagrams- on others objects. This is performed through the use of <strong>special directives</strong> in
the JSON (see in appendix).</p>
<p>A major difference between a complex types defined in the section "definitions" and "inline" is that
"<strong>inline</strong>" complex types are "<strong>anonymous</strong>" :</p>
<pre><code class="language-json" data-keep-tags="strong">...
"definitions": {
"CLASS1" : { "type":"object", // this defines the class "CLASS1"
"properties" : {
"LABEL" : { "type" : "string" },
"SKIP" : { "type" : "boolean" }
}
},
"CLASS2" : { "type":"object", // this defines the class "CLASS2"
"properties" : {
"STR" : { "type" : "string" },
"INTEGER" : { "type" : "integer" }
}
}
}</code></pre>
<p>But "inline" classes are anonymous:</p>
<pre><code class="language-json" data-keep-tags="strong">{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "CONFIG",
"type" : "object",
"properties" : {
"ATTR1" : { "type":"integer"},
"PROPERTY" : { "type":"object",
"properties" : {
"PROP1" : { "type":"number" },
"PROP2" : { "type":"number" },
"PROP3" : { "type":"number" }
}
}
}
} </code></pre>
<p>Indeed, what is the class name of the root object? And what is the class name of the object stored in the "PROPERTY"
element ? </p>
<p>For the <strong>"root class"</strong>, the class name will be per default
"<strong></strong><strong>JSONROOT</strong>". This can be overwritten by specifying in the root <strong>"$comment"</strong> the
following directive: "<strong>##classname#<name>##</strong> <rest of the description>". Then the root class
will be named <strong><name></strong>.</p>
<p>For <strong>"inline" classes</strong>, the class name is per default the name of the tag, here "PROPERTY", or can be
specified in the description following the "<strong>directive</strong>" technique previously used for the root object:
</p>
<pre><code class="special language-json">{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "CONFIG",
"description" : "",
"<strong>$comment</strong>" : "<strong>##classname#CONFIG##</strong> the class for the root object",
"type" : "object",
"properties" : {
"ATTR1" : { "type":"integer" },
"PROPERTY" : { "type":"object", "<strong>$comment</strong>":"<strong>##classname#PROPS##</strong> the class name for this record",
"properties" : {
"PROP1" : { "type":"number" },
"PROP2" : { "type":"number" }
}
}
}
}</code></pre>
<p>So the root class will be named "<strong>CONFIG</strong>" and the "PROPERTY" element will be an object
of type "<strong>PROPS</strong>". Whereever classnames are implicitely or explicitely set, the user must take care
himself that there are no class name "inconsistencies" in the schema. For example, in case of "implicit" class names,
inconsistencies can occur if the element "PROPERTY" is used more than once with different contents : for example, the
following schema would be badly imported:</p>
<pre><code class="language-json" data-keep-tags="strong">{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "CONFIG",
"<strong>$comment</strong>" : "<strong>##classname#CONFIG##</strong> root class name",
"type" : "object",
"properties" : {
"ATTR1" : { "type":"integer" },
"OBJECT2" : { "type":"object",
"ATTR2" : { "type":"integer" },
"<strong>PROPERTY</strong>" : { "type":"object",
"properties" : {
"O1_PROP1" : { "type":"number" },
"O1_PROP2" : { "type":"number" }
}
}
},
"OBJECT2" : { "type":"object",
"ATTR2" : { "type":"integer" },
"<strong>PROPERTY</strong>" : { "type":"object",
"properties" : {
"O2_PROP1" : { "type":"integer" },
"O2_PROP2" : { "type":"number" },
"O2_PROP3" : { "type":"boolean" }
}
}
}
}
}</code></pre>
<p>Indeed, in this case, the class name for the object stored in element "<strong>PROPERTY</strong>" of "OBJECT1" would
be "<strong>PROPERTY</strong>". The class name for the object stored in element "<strong>PROPERTY</strong>" of
"OBJECT2" would be "<strong>PROPERTY</strong>" as well. But their content is obviously different.</p>
<p>To resolve the conflict, changing the names of the attributes can be a solution: </p>
<pre><code class="language-json" data-keep-tags="strong">{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "CONFIG",
"$comment" : "<strong>##classname#CONFIG##</strong> root class name",
"type" : "object",
"properties" : {
"ATTR1" : { "type":"integer },
"OBJECT1" : { "type":"object",
"ATTR1" : { "type":"integer"},
"<strong>OBJECT1_PROPERTY</strong>" : { "type":"object",
"properties" : {
"O1_PROP1" : { "type":"number" },
"O1_PROP2" : { "type":"number" }
}
}
},
"OBJECT2" : { "type":"object",
"ATTR2" : { "type":"integer",
"<strong>OBJECT2_PROPERTY</strong>" : { "type":"object",
"properties" : {
"O2_PROP1" : { "type":"integer" },
"O2_PROP2" : { "type":"number" },
"O2_PROP3" : { "type":"boolean" }
}
}
}
}
}</code></pre>
<p>or, without changing the names of the attributes, by specifying explicitely with the $comment directive trick the
name of the classes:</p>
<pre><code class="language-json" data-keep-tags="strong">{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "CONFIG",
"$comment" : "<strong>##classname#CONFIG##</strong> root class name",
"type" : "object",
"properties" : {
"ATTR1" : { "type":"integer" },
"OBJECT1" : { "type":"object"
"ATTR1" : { "type":"integer" },
"<strong>PROPERTY</strong>" : { "type":"object", "$comment":"<strong>##classname#OBJECT1_PROPERTY##</strong>",
"properties" : {
"O1_PROP1" : { "type":"number" },
"O1_PROP2" : { "type":"number" }
}
}
},
"OBJECT2" : { "type":"object"
"ATTR2" : { "type":"integer" },
"<strong>PROPERTY</strong>" : { "type":"object", "$comment":"<strong>##classname#OBJECT2_PROPERTY##</strong>",
"properties" : {
"O2_PROP1" : { "type":"integer" },
"O2_PROP2" : { "type":"number" },
"O2_PROP3" : { "type":"boolean" }
}
}
}
}
}</code></pre>
<p>Or, finally, the classes names can be given in the "<strong>definitions</strong>" paragraph": </p>
<pre><code class="language-json" data-keep-tags="strong">{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "CONFIG",
"$comment" : "##classname#CONFIG##",
"type" : "object",
"properties" : {
"ATTR1" : { "type":"integer" },
"OBJECT1" : { "type":"object",
"ATTR1" : { "type":"integer" },
"<strong>PROPERTY</strong>" : { <strong>"$ref" : "#/definitions/OBJECT1_PROPERTY"</strong> }
},
"OBJECT2" : { "type":"object",
"ATTR2" : { "type":"integer" },
"<strong>PROPERTY</strong>" : { <strong>"$ref" : "#/definitions/OBJECT2_PROPERTY"</strong> }
}
},
"definitions": {
"<strong>OBJECT1_PROPERTY</strong>" : { "type":"object",
"properties" : {
"O1_PROP1" : { "type":"number" },
"O1_PROP2" : { "type":"number" }
}
},
"<strong>OBJECT2_PROPERTY</strong>": { "type":"object",
"properties" : {
"O2_PROP1" : { "type":"integer" },
"O2_PROP2" : { "type":"number" },
"O2_PROP3" : { "type":"boolean" }
}
}
}
}</code></pre>
<h5 id="L2258">Restrictions of JSON Schemas</h5>
<ul>
<li><strong>"anyOf"</strong> supported only for complex types</li>
<li><strong>"oneOf"</strong> supported only for complex types</li>
<li><strong>"allOf"</strong> supported only for complex types or "complex types + simple attributes" to <strong>define derived classes</strong></li>
<li><strong>"format"</strong> supported only for strings (date-time -Full ISO8601 DateTime-, date, time, email, hostname, ipv4, ipv6, uri)</li>
<li>others ?</li>
</ul>
<h5 id="L2274">"anyOf" tag</h5>
<p>Tags "<strong>anyOf</strong>" is similar to the XSD tags
"<strong>xs:choice</strong>".</p>
<pre><code class="language-json" data-keep-tags="strong">[
{ "LABEL": "label" , "SKIP": true } , ## object of which type ?
{ "STR" : "label" } , ## object of which type ?
{ "LABEL": "label" , "SKIP": true } ## object of which type ?
]</code></pre>
<p>If an array contains objects of only 1 type, array items can be "normally" parsed
(the parser "knows" of which type are the array items).
But in the case of an array containing objects of different types, this is indeed a problem.
How to read correctly the JSON files, i.e. how to recognize the classes of the items being read?
The reader must be able to recognize the types of the objects in the array.
In the PMF framework, this is achieved by imposing on the array items that their classes contain only required attributes.
By analysing the list of keys of an object, the class of the object can be recognized.</p>
<p>The JSON schema then would look likes: </p>
<pre><code class="language-json" data-keep-tags="strong">...
"definitions": {
"MIXED_TYPES_ARRAY" : { "type": "array", "items":
{
"anyOf" :
[
{ "$ref": "#/definitions/<strong>CLASS1</strong>" },
{ "$ref": "#/definitions/<strong>CLASS2</strong>" }
]
}
},
"<strong>CLASS1</strong>" : { "type":"object",
"properties" : {
"LABEL" : { "type" : "string" },
"SKIP" : { "type" : "boolean" }
},
"additionalProperties": false,
"required" : ["LABEL", "SKIP"]
},
"<strong>CLASS2</strong>" : { "type":"object",
"properties" : {
"STR" : { "type" : "string" }
},
"additionalProperties": false,
"required" : ["STR"]
}
}</code></pre>
<p>Nevertheless, there are cases where the design of the schema is such that the "anyOf" array contains objects of
different types, but the different types have the <strong> same attributes</strong>, and only the content of the attributes
allow thus to recognize (hopefully) the class of the items:<p>
<pre><code class="language-json" data-keep-tags="strong">...
"MYLIST" : [
{ "LABEL": "label1" , "INFO": "object of class CLASS1" } ,
{ "LABEL": "label2" , "INFO": "object of class CLASS2" } ,
{ "LABEL": "label3" , "INFO": "object of class CLASS1" } ,
]</code></pre>
<p>Here the content of the <strong>INFO</strong> attributes "indicates" the class of the items.</p>
<p>In this case, the containing class must re-define the method <strong>json_oneof_query_child_class</strong>
in order to select the right class.
The method is re-defined in the generated "Super" class:</p>
<pre><code class="language-python">def json_anyof_query_child_class(self, key, datadict):
'''
'''
if key == "MYLIST":
if datadict["INFO"] == "object of class CLASS1":
return "CLASS1"
if datadict["INFO"] == "object of class CLASS2":
return "CLASS2"
# not found
return None
</code></pre>
<p>Note: the default behavior is to compare the list of attributes of the items with the
classes specified in the "anyOf" definition in the json schema.</p>
<h5 id="L2275">"oneOf" tag</h5>
<p>Tag "<strong>oneOf</strong>" is similar to the XSD tag "<strong>xs:choice</strong>" with
<strong>maxOccurs="1"</strong>.</p>
<pre><code class="language-json" data-keep-tags="strong"> ...
"definitions": {
"ONEOF_OBJECT" : { "type":"object" ,
"oneOf" : [
{ "$ref": "#/definitions/CLASS1" },
{ "$ref": "#/definitions/CLASS2" }
]
},
"CLASS1" : { "type":"object",
"properties" : {
"LABEL" : { "type" : "string" },
"SKIP" : { "type" : "boolean" }
},
"additionalProperties": false,
"required" : ["LABEL", "SKIP"]
},
"CLASS2" : { "type":"object",
"properties" : {
"STR" : { "type" : "string" }
},
"additionalProperties": false,
"required" : ["TYPE", "STR"]
}
}</code></pre>
<p>and a valid JSON file would look like </p>
<pre><code class="language-json" data-keep-tags="strong"> ...
"ONEOF_OBJECT1" : { "LABEL": "label" , "SKIP": true } ,
"ONEOF_OBJECT2" : { "STR" : "label" } ,
"ONEOF_OBJECT3" : { "LABEL": "label" , "SKIP": true} ,
...</code></pre>
<p>Note: for items inside a "oneOf", the "additionalProperties" flag is mandatory and should be set to false for a
succesfull validation</p>
<h5 id="L2276">"allOf" tag</h5>
<p>Tag "<strong>allOf</strong>" allows to defined derived classes.</p>
<p>To define a derived class, declare the class as following:</p>
<pre><code class="language-json" data-keep-tags="strong">
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
},
"location" : {
"type": "object",
"properties": {
"location": { "type": "string", "enum": [ "paris", "london", "new-york" ] }
},
"required": ["location"]
},
<strong>"business_address": </strong> {
"type": "object",
"allOf": [
{ "$ref": "#/definitions/<strong>address</strong>" },
{ "$ref": "#/definitions/<strong>location</strong>" }
]
},
...
</code></pre>
<p>Here the class <code>business_address</code> derives from 2 bases classes <code>address</code> and <code>location</code>.</p>
<p>Or similarly:</p>
<pre><code class="language-json" data-keep-tags="strong">
"shipping_address": {
"type": "object",
"allOf": [
{ "$ref": "#/definitions/<strong>address</strong>" },
{ "properties":
{ "type": { "type": "string", "enum": [ "residential", "business" ] } },
"required": ["type"]
}
]
}
</code></pre>
<p>Here the class <code>shipping_address</code> derives from 1 base classe <code>address</code> and has the extra attribute <code>type</code>.</p>
<p>Note: Definition of classes with <code>allOf</code> with inside only properties (without ref to a base class) is not supported.</p>
<p></p>
<h2 id="L2439">Advanced Usage</h2>
<h3 id="L2589">Mapping of Simple Type to Formular Widgets</h3>
<p>The widgets in the formular are derived from the type of the simple types defined in the schema</p>
<p></p>
<h4 id="L1093">JSON Simple Types Mapping</h4>
<table style="text-align: left; width: 90%;" border="1" cellpadding="2" cellspacing="2">
<col />
<col />
<col />
<col />
<col />
<tbody>
<tr>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 15%;">Schema Type</td>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 15%;">Formular Widget Type</td>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 15%;">Qt Widget Type</td>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 55%;">Details</td>
</tr>
<tr>
<td>"type":"<strong>integer</strong>" </td>
<td>std_integer</td>
<td>Qt spinbox</td>
<td>customizable through <strong>minimum</strong>, <strong>maximum</strong>, <strong>minimumExclusive</strong>
etc...</td>
</tr>
<tr>
<td>"type":"<strong>number</strong>" </td>
<td>std_float </td>
<td>Qt lineedit</td>
<td>with related pattern to allow only float input</td>
</tr>
<tr>
<td>"type":"<strong>boolean</strong>" </td>
<td>std_boolean</td>
<td>Qt checkbox</td>
<td></td>
</tr>
<tr>
<td>"type":"<strong>string</strong>" </td>
<td>std_lineedit</td>
<td>Qt lineedit</td>
<td>default</td>
</tr>
<tr>
<td></td>
<td>std_textedit</td>
<td>Qt textedit</td>
<td>if <strong>minLength/maxLength</strong> is defined in the schema and is larger than 64</td>
</tr>
<tr>
<td></td>
<td>std_datetime</td>
<td>Qt dateEdit</td>
<td>if format "<strong>date-time</strong>"</td>
</tr>
<tr>
<td></td>
<td>std_date</td>
<td>Qt dateEdit</td>
<td>if format "<strong>date</strong>"</td>
</tr>
<tr>
<td></td>
<td>std_time</td>
<td>Qt dateEdit</td>
<td>if format "<strong>time</strong>"</td>
</tr>
<tr>
<td></td>
<td>std_combobox </td>
<td>Qt combobox</td>
<td>when an <strong>enum</strong> is specified in the schema</td>
</tr>
<tr>
<td></td>
<td>std_radiobtns</td>
<td>Qt radiobuttons</td>
<td>when an <strong>enum</strong> is specified in the schema (alternative to std_combobox)</td>
</tr>
<tr>
<td></td>
<td>pmf_browser</td>
<td></td>
<td>compound widget composed of one lineedit and a button to select a data - to be set per hand by the user in
the formular definition</td>
</tr>
<tr>
<td>"type":"<strong>array</strong>"</td>
<td>pmf_simplelist</td>
<td>Qt listview</td>
<td>compound widget to allow addind/removing entries in the list</td>
</tr>
<tr>
<td></td>
<td>std_checkboxlist</td>
<td>Qt check listview</td>
<td>and an <strong>enum</strong> is specified with "<strong>uniqueItem</strong>" for them</td>
</tr>
<tr>
<td></td>
<td>std_checkcombobox</td>
<td>Qt check combobox</td>
<td>and an <strong>enum</strong> is specified with "<strong>uniqueItem</strong>" for them (alternative to
std_checkboxlist)</td>
</tr>
</tbody>
</table>
<p></p>
<p>The importer tries to map the simple types to the "best" widgets depending on the restrictions/properties given in
the schema. Moreover, the generated formulars/formular properties can be edited by hand (in the generated "super"
classes).</p>
<p></p>
<h4 id="L1307">XSD Simple Types Mapping</h4>
<table style="text-align: left; width: 90%;" border="1" cellpadding="2" cellspacing="2">
<col />
<col />
<col />
<col />
<col />
<tbody>
<tr>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 15%;">Schema Type</td>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 15%;">Formular Widget Type</td>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 15%;">Qt Widget Type</td>
<td style="vertical-align: top; background-color: rgb(204, 204, 204); width: 55%;">Details</td>
</tr>
<tr>
<td>xs:time</td>
<td>std_time</td>
<td>Qt timeEdit</td>
<td>with related format</td>
</tr>
<tr>
<td>xs:date</td>
<td>std_date</td>
<td>Qt dateEdit</td>
<td>with related format</td>
</tr>
<tr>
<td>xs:dateTime</td>
<td>std_datetime</td>
<td>Qt dateTimeEdit</td>
<td>with related format</td>
</tr>
<tr>
<td>xs:gDay</td>
<td>std_gDay</td>
<td>Qt dateEdit</td>