1
module m_common_element
4
! Structure and manipulation of element specification
6
use fox_m_fsys_array_str, only: str_vs, vs_str_alloc, vs_vs_alloc
7
use fox_m_fsys_string_list, only: string_list, init_string_list, &
8
destroy_string_list, add_string, tokenize_to_string_list, &
10
use m_common_charset, only: isInitialNameChar, isNameChar, &
11
upperCase, XML_WHITESPACE
12
use m_common_content_model, only: content_particle_t, newCP, destroyCPtree, &
13
OP_MIXED, OP_CHOICE, OP_SEQ, OP_NAME, &
14
REP_QUESTION_MARK, REP_ASTERISK, &
15
transformCPPlus ! , dumpCPtree ! For debugging - see below.
16
use m_common_error, only: error_stack, add_error, in_error
17
use m_common_namecheck, only: checkName, checkNames, checkNCName, &
18
checkNCNames, checkQName, checkNmtoken, checkNmtokens
23
integer, parameter :: ST_START = 0
24
integer, parameter :: ST_EMPTYANY = 1
25
integer, parameter :: ST_FIRSTCHILD = 2
26
integer, parameter :: ST_END = 3
27
integer, parameter :: ST_PCDATA = 4
28
integer, parameter :: ST_NAME = 5
29
integer, parameter :: ST_CHILD = 6
30
integer, parameter :: ST_AFTERBRACKET = 7
31
integer, parameter :: ST_AFTERLASTBRACKET = 8
32
integer, parameter :: ST_SEPARATOR = 9
33
integer, parameter :: ST_AFTERNAME = 10
34
integer, parameter :: ST_ATTTYPE = 11
35
integer, parameter :: ST_AFTER_NOTATION = 12
36
integer, parameter :: ST_NOTATION_LIST = 13
37
integer, parameter :: ST_ENUMERATION = 14
38
integer, parameter :: ST_ENUM_NAME = 15
39
integer, parameter :: ST_AFTER_ATTTYPE_SPACE = 16
40
integer, parameter :: ST_AFTER_ATTTYPE = 17
41
integer, parameter :: ST_DEFAULT_DECL = 18
42
integer, parameter :: ST_AFTERDEFAULTDECL = 19
43
integer, parameter :: ST_DEFAULTVALUE = 20
45
integer, parameter :: ATT_NULL = 0
47
integer, parameter :: ATT_CDATA = 1
48
integer, parameter :: ATT_ID = 2
49
integer, parameter :: ATT_IDREF = 3
50
integer, parameter :: ATT_IDREFS = 4
51
integer, parameter :: ATT_ENTITY = 5
52
integer, parameter :: ATT_ENTITIES = 6
53
integer, parameter :: ATT_NMTOKEN = 7
54
integer, parameter :: ATT_NMTOKENS = 8
55
integer, parameter :: ATT_NOTATION = 9
56
integer, parameter :: ATT_ENUM = 10
57
integer, parameter :: ATT_CDANO = 11
58
integer, parameter :: ATT_CDAMB = 12
60
character(len=8), parameter :: ATT_TYPES(12) = (/ &
74
integer, parameter :: ATT_REQUIRED = 1
75
integer, parameter :: ATT_IMPLIED = 2
76
integer, parameter :: ATT_DEFAULT = 4
77
integer, parameter :: ATT_FIXED = 3
81
character, pointer :: name(:) => null()
82
integer :: attType = ATT_NULL
83
integer :: attDefault = ATT_NULL
84
type(string_list) :: enumerations
85
character, pointer :: default(:) => null()
86
logical :: internal = .true.
90
type(attribute_t), pointer :: list(:) => null()
91
end type attribute_list
94
character, pointer :: name(:) => null()
95
logical :: empty = .false.
96
logical :: any = .false.
97
logical :: mixed = .false.
98
logical :: id_declared = .false.
99
logical :: internal = .true.
100
type (content_particle_t), pointer :: cp => null()
101
character, pointer :: model(:) => null()
102
type(attribute_list) :: attlist
106
type(element_t), pointer :: list(:) => null()
107
end type element_list
111
public :: element_list
113
public :: attribute_t
114
public :: attribute_list
116
public :: init_element_list
117
public :: destroy_element_list
118
public :: existing_element
119
public :: declared_element
120
public :: get_element
121
public :: add_element
123
public :: parse_dtd_element
125
public :: init_attribute_list
126
public :: destroy_attribute_list
129
public :: parse_dtd_attlist
131
public :: report_declarations
133
public :: attribute_has_default
134
public :: get_attlist_size
135
public :: get_attribute_declaration
136
public :: express_attribute_declaration
138
public :: att_value_normalize
140
public :: get_att_type_enum
148
public :: ATT_ENTITIES
149
public :: ATT_NMTOKEN
150
public :: ATT_NMTOKENS
151
public :: ATT_NOTATION
157
public :: ATT_REQUIRED
158
public :: ATT_IMPLIED
159
public :: ATT_DEFAULT
164
interface get_attribute_declaration
165
module procedure get_attdecl_by_index
166
module procedure get_attdecl_by_name
171
subroutine init_element_list(e_list)
172
type(element_list), intent(inout) :: e_list
174
allocate(e_list%list(0))
175
end subroutine init_element_list
177
subroutine destroy_element_list(e_list)
178
type(element_list), intent(inout) :: e_list
182
do i = 1, size(e_list%list)
183
deallocate(e_list%list(i)%name)
184
if (associated(e_list%list(i)%cp)) call destroyCPtree(e_list%list(i)%cp)
185
if (associated(e_list%list(i)%model)) deallocate(e_list%list(i)%model)
186
call destroy_attribute_list(e_list%list(i)%attlist)
188
deallocate(e_list%list)
189
end subroutine destroy_element_list
191
function existing_element(e_list, name) result(p)
192
type(element_list), intent(in) :: e_list
193
character(len=*), intent(in) :: name
199
do i = 1, size(e_list%list)
200
if (str_vs(e_list%list(i)%name)==name) then
205
end function existing_element
207
function declared_element(e_list, name) result(p)
208
type(element_list), intent(in) :: e_list
209
character(len=*), intent(in) :: name
215
do i = 1, size(e_list%list)
216
if (str_vs(e_list%list(i)%name)==name) then
217
p = associated(e_list%list(i)%model)
221
end function declared_element
223
function get_element(e_list, name) result(e)
224
type(element_list), intent(in) :: e_list
225
character(len=*), intent(in) :: name
226
type(element_t), pointer :: e
230
do i = 1, size(e_list%list)
231
if (str_vs(e_list%list(i)%name)==name) then
237
end function get_element
239
function add_element(e_list, name) result(e)
240
type(element_list), intent(inout) :: e_list
241
character(len=*), intent(in) :: name
242
type(element_t), pointer :: e
244
type(element_t), pointer :: temp(:)
249
allocate(e_list%list(size(temp)+1))
251
e_list%list(i)%name => temp(i)%name
252
e_list%list(i)%model => temp(i)%model
253
e_list%list(i)%empty = temp(i)%empty
254
e_list%list(i)%any = temp(i)%any
255
e_list%list(i)%mixed = temp(i)%mixed
256
e_list%list(i)%cp => temp(i)%cp
257
e_list%list(i)%id_declared = temp(i)%id_declared
258
e_list%list(i)%internal = temp(i)%internal
259
e_list%list(i)%attlist%list => temp(i)%attlist%list
263
e%name => vs_str_alloc(name)
264
call init_attribute_list(e%attlist)
266
end function add_element
268
subroutine parse_dtd_element(contents, xv, stack, element, internal)
269
character(len=*), intent(in) :: contents
270
integer, intent(in) :: xv
271
type(error_stack), intent(inout) :: stack
272
type(element_t), pointer :: element
273
logical, intent(in) :: internal
276
integer :: i, nbrackets
277
logical :: mixed, empty, any
279
character, pointer :: order(:), name(:), temp(:)
280
type(content_particle_t), pointer :: top, current, tcp
281
logical :: mixed_additional, firstChild
283
! FIXME should we check namespaces here (for element names)
284
! checking duplicates - valid or wf? - and only for MIXED?
294
mixed_additional = .false.
300
do i = 1, len(contents) + 1
301
if (i<=len(contents)) then
307
if (state==ST_START) then
308
!write(*,*)'ST_START'
309
if (verify(c, XML_WHITESPACE)==0) then
311
elseif (verify(c, 'EMPTYANY')==0) then
312
name => vs_str_alloc(c)
315
order => vs_str_alloc(" ")
319
state = ST_FIRSTCHILD
321
call add_error(stack, &
322
'Unexpected character "'//c//'" at start of ELEMENT specification')
326
elseif (state==ST_EMPTYANY) then
327
!write(*,*)'ST_EMPTYANY'
328
if (verify(c, upperCase)==0) then
330
name => vs_str_alloc(str_vs(temp)//c)
332
elseif (verify(c, XML_WHITESPACE)==0) then
333
if (str_vs(name)=='EMPTY') then
335
top => newCP(empty=.true.)
337
elseif (str_vs(name)=='ANY') then
339
top => newCP(any=.true.)
342
call add_error(stack, &
343
'Unexpected ELEMENT specification; expecting EMPTY or ANY')
349
call add_error(stack, &
350
'Unexpected ELEMENT specification; expecting EMPTY or ANY')
354
elseif (state==ST_FIRSTCHILD) then
355
!write(*,*)'ST_FIRSTCHILD'
356
if (verify(c, XML_WHITESPACE)==0) cycle
360
name => vs_str_alloc("")
361
elseif (isInitialNameChar(c, xv)) then
366
nbrackets = nbrackets + 1
369
current%firstChild => tcp
370
tcp%parent => current
372
order => vs_str_alloc(" ")
375
call add_error(stack, &
376
'Unexpected character in ELEMENT specification')
380
elseif (state==ST_PCDATA) then
381
!write(*,*)'ST_PCDATA'
382
if (verify(c, 'PCDATA')==0) then
384
name => vs_str_alloc(str_vs(temp)//c)
386
elseif (verify(c, XML_WHITESPACE)==0) then
387
if (str_vs(name)=='PCDATA') then
390
call add_error(stack, &
391
'Unexpected token after #')
394
! Must be first child
395
current%operator = OP_MIXED
396
tcp => newCP(name="#PCDATA")
397
current%firstChild => tcp
398
tcp%parent => current
403
if (str_vs(name)=='PCDATA') then
406
state = ST_AFTERLASTBRACKET
409
call add_error(stack, &
410
'Unexpected token after #')
413
! Must be first child
414
current%operator = OP_MIXED
415
tcp => newCP(name="#PCDATA")
416
current%firstChild => tcp
417
tcp%parent => current
420
if (str_vs(name)=='PCDATA') then
424
call add_error(stack, &
425
'Unexpected token after #')
428
! Must be first child
429
current%operator = OP_MIXED
430
tcp => newCP(name="#PCDATA")
431
current%firstChild => tcp
432
tcp%parent => current
438
call add_error(stack, &
439
'Ordered specification not allowed for Mixed elements')
442
call add_error(stack, &
443
'Unexpected character in ELEMENT specification')
447
elseif (state==ST_NAME) then
449
if (isNameChar(c, xv)) then
451
name => vs_str_alloc(str_vs(temp)//c)
453
elseif (scan(c, "?+*")>0) then
455
call add_error(stack, &
456
'Repeat operators forbidden for Mixed elements')
459
tcp => newCP(name=str_vs(name), repeat=c)
462
current%firstChild => tcp
463
tcp%parent => current
466
current%nextSibling => tcp
467
tcp%parent => current%parent
470
if (c=="+") call transformCPPlus(current)
472
elseif (verify(c, XML_WHITESPACE)==0) then
473
if (mixed) mixed_additional = .true.
474
tcp => newCP(name=str_vs(name))
477
current%firstChild => tcp
478
tcp%parent => current
481
current%nextSibling => tcp
482
tcp%parent => current%parent
486
elseif (scan(c,',|')>0) then
487
if (order(nbrackets)=='') then
489
elseif (order(nbrackets)/=c) then
490
call add_error(stack, &
491
'Cannot mix ordered and unordered elements')
494
if (mixed) mixed_additional = .true.
495
tcp => newCP(name=str_vs(name))
498
current%firstChild => tcp
499
tcp%parent => current
502
current%nextSibling => tcp
503
tcp%parent => current%parent
506
if (c=="|".and.current%parent%operator/=OP_MIXED) &
507
current%parent%operator = OP_CHOICE
510
if (mixed) mixed_additional = .true.
511
nbrackets = nbrackets - 1
512
if (nbrackets==0) then
513
state = ST_AFTERLASTBRACKET
517
allocate(order(nbrackets))
518
order = temp(:size(order))
520
state = ST_AFTERBRACKET
522
tcp => newCP(name=str_vs(name))
525
current%firstChild => tcp
526
tcp%parent => current
529
current%nextSibling => tcp
530
tcp%parent => current%parent
531
current => current%parent
532
if (.not.check_duplicates(current)) &
536
call add_error(stack, &
537
'Unexpected character found after element name')
541
elseif (state==ST_CHILD) then
542
!write(*,*)'ST_CHILD'
543
if (verify(c, XML_WHITESPACE)==0) cycle
545
call add_error(stack, &
546
'# forbidden except as first child element')
548
elseif (isInitialNameChar(c, xv)) then
549
name => vs_str_alloc(c)
553
call add_error(stack, &
554
'Nested brackets forbidden for Mixed content')
559
current%firstChild => tcp
560
tcp%parent => current
562
current%nextSibling => tcp
563
tcp%parent => current%parent
567
nbrackets = nbrackets + 1
569
order => vs_str_alloc(str_vs(temp)//" ")
572
call add_error(stack, &
573
'Unexpected character "'//c//'" found after (')
577
elseif (state==ST_SEPARATOR) then
578
!write(*,*)'ST_SEPARATOR'
579
if (verify(c, XML_WHITESPACE)==0) cycle
581
call add_error(stack, &
582
'#PCDATA must be first in list')
584
elseif (scan(c,'|,')>0) then
585
if (order(nbrackets)=='') then
587
elseif (order(nbrackets)/=c) then
588
call add_error(stack, &
589
'Cannot mix ordered and unordered elements')
592
if (c=="|".and.current%parent%operator/=OP_MIXED) &
593
current%parent%operator = OP_CHOICE
596
nbrackets = nbrackets - 1
597
if (nbrackets==0) then
598
state = ST_AFTERLASTBRACKET
602
allocate(order(nbrackets))
603
order = temp(:size(order))
605
state = ST_AFTERBRACKET
607
current => current%parent
608
if (.not.check_duplicates(current)) &
611
call add_error(stack, &
612
'Unexpected character found in element declaration.')
616
elseif (state==ST_AFTERBRACKET) then
617
!write(*,*)'ST_AFTERBRACKET'
619
current%repeater = REP_ASTERISK
622
call transformCPPlus(current)
625
current%repeater = REP_QUESTION_MARK
627
elseif (verify(c, XML_WHITESPACE)==0) then
629
elseif (scan(c,'|,')>0) then
630
if (order(nbrackets)=='') then
632
elseif (order(nbrackets)/=c) then
633
call add_error(stack, &
634
'Cannot mix ordered and unordered elements')
637
if (c=="|".and.current%parent%operator/=OP_MIXED) &
638
current%parent%operator = OP_CHOICE
641
nbrackets = nbrackets - 1
642
if (nbrackets==0) then
644
state = ST_AFTERLASTBRACKET
647
allocate(order(nbrackets))
648
order = temp(:size(order))
650
state = ST_AFTERBRACKET
652
current => current%parent
653
if (.not.check_duplicates(current)) &
656
call add_error(stack, &
657
'Unexpected character "'//c//'"found after ")"')
661
elseif (state==ST_AFTERLASTBRACKET) then
662
!write(*,*)'ST_AFTERLASTBRACKET'
665
current%repeater = REP_ASTERISK
668
call add_error(stack, &
669
'+ operator disallowed for Mixed elements')
672
call transformCPPlus(current)
676
call add_error(stack, &
677
'? operator disallowed for Mixed elements')
680
current%repeater = REP_QUESTION_MARK
682
elseif (verify(c, XML_WHITESPACE)==0) then
684
if (mixed_additional) then
685
call add_error(stack, &
686
'Missing "*" at end of Mixed element specification')
692
call add_error(stack, &
693
'Unexpected character "'//c//'" found after final ")"')
697
elseif (state==ST_END) then
699
if (verify(c, XML_WHITESPACE)==0) then
702
call add_error(stack, &
703
'Unexpected token found after end of element specification')
711
if (state/=ST_END) then
712
call add_error(stack, "Error in parsing contents of element declaration")
716
if (associated(element)) then
718
element%empty = empty
719
element%mixed = mixed
720
element%model => vs_str_alloc(trim(strip_spaces(contents)))
722
element%internal = internal
723
! For debugging it may be useful to dump the result here...
724
! Also need to use the subroutine.
725
! call dumpCPtree(top)
727
if (associated(top)) call destroyCPtree(top)
731
100 if (associated(order)) deallocate(order)
732
if (associated(name)) deallocate(name)
733
if (associated(top)) call destroyCPtree(top)
736
function strip_spaces(s1) result(s2)
737
character(len=*) :: s1
738
character(len=len(s1)) :: s2
742
if (verify(s1(i:i), XML_WHITESPACE)==0) cycle
747
end function strip_spaces
749
function check_duplicates(cp) result(p)
750
type(content_particle_t), pointer :: cp
753
type(string_list) :: sl
754
type(content_particle_t), pointer :: tcp
756
if (cp%operator==OP_SEQ) then
761
call init_string_list(sl)
764
do while (associated(tcp))
765
if (tcp%operator==OP_NAME) then
766
if (registered_string(sl, str_vs(tcp%name))) then
767
call destroy_string_list(sl)
768
if (cp%operator==OP_MIXED) then
769
call add_error(stack, &
770
"Duplicate element names found in MIXED")
771
elseif (cp%operator==OP_CHOICE) then
772
call add_error(stack, &
773
"Duplicate element names found in CHOICE")
777
call add_string(sl, str_vs(tcp%name))
780
tcp => tcp%nextSibling
783
call destroy_string_list(sl)
784
end function check_duplicates
785
end subroutine parse_dtd_element
788
subroutine init_attribute_list(a_list)
789
type(attribute_list), intent(inout) :: a_list
791
allocate(a_list%list(0))
792
end subroutine init_attribute_list
794
subroutine destroy_attribute_t(a)
795
type(attribute_t), pointer :: a
797
if (associated(a%name)) deallocate(a%name)
798
if (associated(a%default)) deallocate(a%default)
799
call destroy_string_list(a%enumerations)
802
end subroutine destroy_attribute_t
804
subroutine destroy_attribute_list(a_list)
805
type(attribute_list), intent(inout) :: a_list
809
do i = 1, size(a_list%list)
810
deallocate(a_list%list(i)%name)
811
if (associated(a_list%list(i)%default)) deallocate(a_list%list(i)%default)
812
call destroy_string_list(a_list%list(i)%enumerations)
814
deallocate(a_list%list)
816
end subroutine destroy_attribute_list
818
function existing_attribute(a_list, name) result(p)
819
type(attribute_list), intent(inout) :: a_list
820
character(len=*), intent(in) :: name
825
do i = 1, size(a_list%list)
826
p = (str_vs(a_list%list(i)%name)==name)
829
end function existing_attribute
831
function add_attribute(a_list, name, internal) result(a)
832
type(attribute_list), intent(inout) :: a_list
833
character(len=*), intent(in) :: name
834
logical, intent(in) :: internal
835
type(attribute_t), pointer :: a
838
type(attribute_t), pointer :: temp(:)
841
allocate(a_list%list(size(temp)+1))
843
a_list%list(i)%name => temp(i)%name
844
a_list%list(i)%atttype = temp(i)%atttype
845
a_list%list(i)%attdefault = temp(i)%attdefault
846
a_list%list(i)%default => temp(i)%default
847
a_list%list(i)%enumerations%list => temp(i)%enumerations%list
848
a_list%list(i)%internal = temp(i)%internal
853
a%name => vs_str_alloc(name)
854
call init_string_list(a%enumerations)
855
a%internal = internal
857
end function add_attribute
859
function get_attribute(a_list, name) result(a)
860
type(attribute_list), intent(inout) :: a_list
861
character(len=*), intent(in) :: name
862
type(attribute_t), pointer :: a
865
do i = 1, size(a_list%list)
866
if (str_vs(a_list%list(i)%name)==name) then
871
end function get_attribute
873
subroutine parse_dtd_attlist(contents, xv, namespaces, validCheck, stack, elem, internal)
874
character(len=*), intent(in) :: contents
875
integer, intent(in) :: xv
876
logical, intent(in) :: validCheck
877
logical, intent(in) :: namespaces
878
type(error_stack), intent(inout) :: stack
879
type(element_t), pointer :: elem
880
logical, intent(in) :: internal
885
character, pointer :: name(:), attType(:), default(:), value(:), temp(:)
887
type(attribute_t), pointer :: ca
888
type(attribute_t), pointer :: ignore_att
891
! We need ignore_att to process but not take account of duplicate attributes
892
! elem is optional so we can not record declarations if necessary.
902
do i = 1, len(contents) + 1
903
if (in_error(stack)) exit
904
if (i<=len(contents)) then
910
if (state==ST_START) then
911
!write(*,*)'ST_START'
912
if (verify(c, XML_WHITESPACE)==0) cycle
913
if (isInitialNameChar(c, xv)) then
914
name => vs_str_alloc(c)
917
call add_error(stack, &
918
'Unexpected character in Attlist')
921
elseif (state==ST_NAME) then
923
if (isNameChar(c, xv)) then
924
temp => vs_str_alloc(str_vs(name)//c)
927
elseif (verify(c, XML_WHITESPACE)==0) then
928
if (namespaces.and..not.checkQName(str_vs(name), xv)) then
929
call add_error(stack, &
930
"Attribute name in ATTLIST must be QName")
931
elseif (associated(elem)) then
932
if (existing_attribute(elem%attlist, str_vs(name))) then
933
if (associated(ignore_att)) call destroy_attribute_t(ignore_att)
935
call init_string_list(ignore_att%enumerations)
936
ignore_att%name => vs_vs_alloc(name)
939
ca => add_attribute(elem%attlist, str_vs(name), internal)
942
if (associated(ignore_att)) call destroy_attribute_t(ignore_att)
944
call init_string_list(ignore_att%enumerations)
945
ignore_att%name => vs_vs_alloc(name)
951
call add_error(stack, &
952
'Unexpected character in Attlist Name')
955
elseif (state==ST_AFTERNAME) then
956
!write(*,*)'ST_AFTERNAME'
957
if (verify(c, XML_WHITESPACE)==0) cycle
958
if (verify(c, upperCase)==0) then
959
attType => vs_str_alloc(c)
963
ca%attType = ATT_ENUM
964
state = ST_ENUMERATION
966
call add_error(stack, &
967
'Unexpected error after Attlist Name')
970
elseif (state==ST_ATTTYPE) then
971
!write(*,*)'ST_ATTTYPE'
972
if (verify(c, upperCase)==0) then
974
attType => vs_str_alloc(str_vs(temp)//c)
976
elseif (verify(c, XML_WHITESPACE)==0) then
978
if (str_vs(ca%name)=="xml:id" &
979
.and..not.str_vs(attType)=="ID") then
980
call add_error(stack, &
981
"xml:id attribute must be declared as type ID")
982
elseif (str_vs(attType)=='CDATA') then
983
ca%attType = ATT_CDATA
984
state = ST_AFTER_ATTTYPE
985
elseif (str_vs(attType)=='ID') then
987
! Validity Constraint: One ID per Element Type
988
if (associated(elem)) then
989
if (elem%id_declared) then
990
call add_error(stack, &
991
"Cannot have two declared attributes of type ID on one element type.")
993
elem%id_declared = .true.
998
state = ST_AFTER_ATTTYPE
999
elseif (str_vs(attType)=='IDREF') then
1000
ca%attType = ATT_IDREF
1001
state = ST_AFTER_ATTTYPE
1002
elseif (str_vs(attType)=='IDREFS') then
1003
ca%attType = ATT_IDREFS
1004
state = ST_AFTER_ATTTYPE
1005
elseif (str_vs(attType)=='ENTITY') then
1006
ca%attType = ATT_ENTITY
1007
state = ST_AFTER_ATTTYPE
1008
elseif (str_vs(attType)=='ENTITIES') then
1009
ca%attType = ATT_ENTITIES
1010
state = ST_AFTER_ATTTYPE
1011
elseif (str_vs(attType)=='NMTOKEN') then
1012
ca%attType = ATT_NMTOKEN
1013
state = ST_AFTER_ATTTYPE
1014
elseif (str_vs(attType)=='NMTOKENS') then
1015
ca%attType = ATT_NMTOKENS
1016
state = ST_AFTER_ATTTYPE
1017
elseif (str_vs(attType)=='NOTATION') then
1018
ca%attType = ATT_NOTATION
1019
state = ST_AFTER_NOTATION
1021
call add_error(stack, &
1026
call add_error(stack, &
1027
'Unexpected character in AttType')
1030
elseif (state==ST_AFTER_NOTATION) then
1031
!write(*,*)'ST_AFTER_NOTATION'
1032
if (verify(c, XML_WHITESPACE)==0) cycle
1034
state = ST_NOTATION_LIST
1036
call add_error(stack, &
1037
'Unexpected character after Notation')
1040
elseif (state==ST_NOTATION_LIST) then
1041
!write(*,*)'ST_NOTATION_LIST'
1042
if (verify(c, XML_WHITESPACE)==0) cycle
1043
if (isInitialNameChar(c, xv)) then
1044
value => vs_str_alloc(c)
1045
state = ST_ENUM_NAME
1047
call add_error(stack, &
1048
'Unexpected character in Notation list')
1051
elseif (state==ST_ENUMERATION) then
1052
!write(*,*)'ST_ENUMERATION'
1053
if (verify(c, XML_WHITESPACE)==0) cycle
1054
if (isNameChar(c, xv)) then
1055
temp => vs_str_alloc(str_vs(value)//c)
1058
state = ST_ENUM_NAME
1059
elseif (c=='|') then
1060
call add_error(stack, &
1061
"Missing token in Enumeration")
1062
elseif (c==')') then
1063
call add_error(stack, &
1064
"Missing tokens in Enumeration")
1066
call add_error(stack, &
1067
'Unexpected character in attlist enumeration')
1070
elseif (state==ST_ENUM_NAME) then
1071
!write(*,*)'ST_ENUM_NAME'
1072
if (isNameChar(c, xv)) then
1073
temp => vs_str_alloc(str_vs(value)//c)
1076
elseif (verify(c, XML_WHITESPACE)==0) then
1077
if (validCheck.and.registered_string(ca%enumerations, str_vs(value))) then
1078
call add_error(stack, &
1079
"Duplicate enumeration value in ATTLIST")
1080
elseif (namespaces.and.ca%attType==ATT_NOTATION &
1081
.and..not.checkNCName(str_vs(value), xv)) then
1082
call add_error(stack, &
1083
"Notation name must be NCName")
1085
call add_string(ca%enumerations, str_vs(value))
1088
state = ST_SEPARATOR
1089
elseif (c=='|') then
1090
if (validCheck.and.registered_string(ca%enumerations, str_vs(value))) then
1091
call add_error(stack, &
1092
"Duplicate enumeration value in ATTLIST")
1093
elseif (namespaces.and.ca%attType==ATT_NOTATION &
1094
.and..not.checkNCName(str_vs(value), xv)) then
1095
call add_error(stack, &
1096
"Notation name must be NCName")
1098
call add_string(ca%enumerations, str_vs(value))
1101
if (ca%attType==ATT_NOTATION) then
1102
state = ST_NOTATION_LIST
1105
state = ST_ENUMERATION
1107
elseif (c==')') then
1108
if (size(value)==0) then
1109
call add_error(stack, &
1110
'Missing token in Enumeration list')
1112
if (validCheck.and.registered_string(ca%enumerations, str_vs(value))) then
1113
call add_error(stack, &
1114
"Duplicate enumeration value in ATTLIST")
1115
elseif (namespaces.and.ca%attType==ATT_NOTATION &
1116
.and..not.checkNCName(str_vs(value), xv)) then
1117
call add_error(stack, &
1118
"Notation name must be NCName")
1120
call add_string(ca%enumerations, str_vs(value))
1123
state = ST_AFTER_ATTTYPE_SPACE
1125
call add_error(stack, &
1126
'Unexpected character in attlist enumeration')
1129
elseif (state==ST_SEPARATOR) then
1130
!write(*,*)'ST_SEPARATOR'
1131
if (verify(c, XML_WHITESPACE)==0) cycle
1133
if (ca%attType==ATT_NOTATION) then
1134
state = ST_NOTATION_LIST
1137
state = ST_ENUMERATION
1139
elseif (c==')') then
1140
state = ST_AFTER_ATTTYPE_SPACE
1142
call add_error(stack, &
1143
'Unexpected character in attlist enumeration')
1146
elseif (state==ST_AFTER_ATTTYPE_SPACE) then
1147
if (verify(c, XML_WHITESPACE)/=0) then
1148
call add_error(stack, &
1149
'Missing whitespace in attlist enumeration')
1151
state = ST_AFTER_ATTTYPE
1153
elseif (state==ST_AFTER_ATTTYPE) then
1154
!write(*,*)'ST_AFTER_ATTTYPE'
1155
if (verify(c, XML_WHITESPACE)==0) cycle
1157
allocate(default(0))
1158
state = ST_DEFAULT_DECL
1159
elseif (c=='"'.or.c=="'") then
1160
if (validCheck) then
1161
! Validity Constraint: ID Attribute Default
1162
if (ca%attType==ATT_ID) &
1163
call add_error(stack, &
1164
"Attribute of type ID may not have default value")
1166
ca%attDefault = ATT_DEFAULT
1169
state = ST_DEFAULTVALUE
1171
call add_error(stack, &
1172
'Unexpected character after AttType')
1175
elseif (state==ST_DEFAULT_DECL) then
1176
!write(*,*)'ST_DEFAULT_DECL'
1177
if (verify(c, upperCase)==0) then
1178
temp => vs_str_alloc(str_vs(default)//c)
1181
elseif (verify(c, XML_WHITESPACE)==0) then
1182
if (str_vs(default)=='REQUIRED') then
1183
ca%attdefault = ATT_REQUIRED
1186
elseif (str_vs(default)=='IMPLIED') then
1187
ca%attdefault = ATT_IMPLIED
1190
elseif (str_vs(default)=='FIXED') then
1191
if (validCheck) then
1192
! Validity Constraint: ID Attribute Default
1193
if (ca%attType==ATT_ID) &
1194
call add_error(stack, &
1195
"Attribute of type ID may not have FIXED value")
1197
ca%attdefault = ATT_FIXED
1199
state = ST_AFTERDEFAULTDECL
1201
call add_error(stack, &
1202
'Unknown Default declaration')
1205
call add_error(stack, &
1206
'Unexpected character in Default declaration')
1209
elseif (state==ST_AFTERDEFAULTDECL) then
1210
!write(*,*)'ST_AFTERDEFAULTDECL'
1211
if (verify(c, XML_WHITESPACE)==0) cycle
1215
state = ST_DEFAULTVALUE
1216
elseif (c=="'") then
1219
state = ST_DEFAULTVALUE
1221
call add_error(stack, &
1222
'Unexpected character after Default declaration')
1225
elseif (state==ST_DEFAULTVALUE) then
1226
!write(*,*)'ST_DEFAULTVALUE'
1228
if (ca%attType/=ATT_CDATA) then
1229
temp => vs_str_alloc(att_value_normalize(str_vs(value)))
1233
if (validCheck) then
1234
select case(ca%attType)
1235
! Can't have ID with defaults
1238
if (namespaces) then
1239
if (.not.checkNCName(str_vs(value), xv)) &
1240
call add_error(stack, &
1241
"Attributes of type IDREF must have a value which is an XML NCName")
1243
if (.not.checkName(str_vs(value), xv)) &
1244
call add_error(stack, &
1245
"Attributes of type IDREF must have a value which is an XML Name")
1249
if (namespaces) then
1250
if (.not.checkNCNames(str_vs(value), xv)) &
1251
call add_error(stack, &
1252
"Attributes of type IDREFS must have a value which contains only XML NCNames")
1254
if (.not.checkNames(str_vs(value), xv)) &
1255
call add_error(stack, &
1256
"Attributes of type IDREFS must have a value which contains only XML Names")
1260
if (namespaces) then
1261
if (.not.checkNCName(str_vs(value), xv)) &
1262
call add_error(stack, &
1263
"Attributes of type ENTITY must have a value which is an XML NCName")
1265
if (.not.checkName(str_vs(value), xv)) &
1266
call add_error(stack, &
1267
"Attributes of type ENTITY must have a value which is an XML Name")
1271
if (namespaces) then
1272
if (.not.checkNames(str_vs(value), xv)) &
1273
call add_error(stack, &
1274
"Attributes of type ENTITIES must have a value which contains only XML NCNames")
1276
if (.not.checkNames(str_vs(value), xv)) &
1277
call add_error(stack, &
1278
"Attributes of type ENTITIES must have a value which contains only XML Names")
1282
if (.not.checkNmtoken(str_vs(value), xv)) &
1283
call add_error(stack, &
1284
"Attributes of type NMTOKEN must have a value which is a NMTOKEN")
1287
if (.not.checkNmtokens(str_vs(value), xv)) &
1288
call add_error(stack, &
1289
"Attributes of type NMTOKENS must have a value which contain only NMTOKENs")
1291
! VC: Notation Attributes
1292
if (namespaces) then
1293
if (.not.checkNCName(str_vs(value), xv)) &
1294
call add_error(stack, &
1295
"Attributes of type NOTATION must have a value which is an XMLNCName")
1297
if (.not.checkName(str_vs(value), xv)) &
1298
call add_error(stack, &
1299
"Attributes of type NOTATION must have a value which is an XML Name")
1303
if (.not.checkNmtoken(str_vs(value), xv)) &
1304
call add_error(stack, &
1305
"Attributes of type ENUM must have a value which is an NMTOKENs")
1306
if (.not.registered_string(ca%enumerations, str_vs(value))) &
1307
call add_error(stack, &
1308
"Default value of ENUM does not match permitted values")
1311
if (.not.in_error(stack)) then
1312
if (ca%attType==ATT_ENTITIES) then
1313
call destroy_string_list(ca%enumerations)
1314
ca%enumerations = tokenize_to_string_list(str_vs(value))
1321
temp => vs_str_alloc(str_vs(value)//c)
1330
if (associated(ignore_att)) call destroy_attribute_t(ignore_att)
1332
if (.not.in_error(stack)) then
1333
if (state==ST_START) then
1336
call add_error(stack, &
1337
'Incomplete Attlist declaration')
1341
if (associated(name)) deallocate(name)
1342
if (associated(attType)) deallocate(attType)
1343
if (associated(default)) deallocate(default)
1344
if (associated(value)) deallocate(value)
1346
end subroutine parse_dtd_attlist
1348
subroutine report_declarations(elem, attributeDecl_handler)
1349
type(element_t), intent(in) :: elem
1351
subroutine attributeDecl_handler(eName, aName, type, mode, value)
1352
character(len=*), intent(in) :: eName
1353
character(len=*), intent(in) :: aName
1354
character(len=*), intent(in) :: type
1355
character(len=*), intent(in), optional :: mode
1356
character(len=*), intent(in), optional :: value
1357
end subroutine attributeDecl_handler
1361
character(len=8) :: type
1362
character(len=8) :: mode
1363
type(attribute_t), pointer :: a
1365
do i = 1, size(elem%attlist%list)
1366
a => elem%attlist%list(i)
1367
type = ATT_TYPES(a%attType)
1368
select case (a%attDefault)
1377
if (a%attType==ATT_NOTATION) then
1378
if (a%attDefault==ATT_DEFAULT) then
1379
if (associated(a%default)) then
1380
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1381
'NOTATION '//make_token_group(a%enumerations), value=str_vs(a%default))
1383
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1384
'NOTATION '//make_token_group(a%enumerations))
1387
if (associated(a%default)) then
1388
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1389
'NOTATION '//make_token_group(a%enumerations), mode=trim(mode), &
1390
value=str_vs(a%default))
1392
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1393
'NOTATION '//make_token_group(a%enumerations), mode=trim(mode))
1396
elseif (a%attType==ATT_ENUM) then
1397
if (a%attDefault==ATT_DEFAULT) then
1398
if (associated(a%default)) then
1399
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1400
make_token_group(a%enumerations), value=str_vs(a%default))
1402
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1403
make_token_group(a%enumerations))
1406
if (associated(a%default)) then
1407
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1408
make_token_group(a%enumerations), mode=trim(mode), &
1409
value=str_vs(a%default))
1411
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1412
make_token_group(a%enumerations), mode=trim(mode))
1416
if (a%attDefault==ATT_DEFAULT) then
1417
if (associated(a%default)) then
1418
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1419
trim(type), value=str_vs(a%default))
1421
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1425
if (associated(a%default)) then
1426
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1427
trim(type), mode=trim(mode), value=str_vs(a%default))
1429
call attributeDecl_handler(str_vs(elem%name), str_vs(a%name), &
1430
trim(type), mode=trim(mode))
1437
end subroutine report_declarations
1439
pure function make_token_group_len(s_list) result(n)
1440
type(string_list), intent(in) :: s_list
1444
n = size(s_list%list) + 1
1445
do i = 1, size(s_list%list)
1446
n = n + size(s_list%list(i)%s)
1448
end function make_token_group_len
1450
function make_token_group(s_list) result(s)
1451
type(string_list), intent(in) :: s_list
1452
character(len=make_token_group_len(s_list)) :: s
1457
do i = 1, size(s_list%list)-1
1458
m = size(s_list%list(i)%s)
1459
s(n:n+m) = str_vs(s_list%list(i)%s)//'|'
1462
s(n:) = str_vs(s_list%list(i)%s)//')'
1463
end function make_token_group
1465
function attribute_has_default(att) result(p)
1466
type(attribute_t), pointer :: att
1469
if (associated(att)) then
1470
p = att%attDefault==ATT_DEFAULT.or.att%attDefault==ATT_FIXED
1474
end function attribute_has_default
1476
function get_attlist_size(elem) result(n)
1477
type(element_t), pointer :: elem
1480
if (associated(elem)) then
1481
n = size(elem%attlist%list)
1485
end function get_attlist_size
1487
function get_attdecl_by_index(elem, n) result(att)
1488
type(element_t), pointer :: elem
1489
integer, intent(in) :: n
1490
type(attribute_t), pointer :: att
1493
if (associated(elem)) then
1494
if (n>0.and.n<=size(elem%attlist%list)) then
1495
att => elem%attlist%list(n)
1498
end function get_attdecl_by_index
1500
function get_attdecl_by_name(elem, name) result(att)
1501
type(element_t), pointer :: elem
1502
character(len=*), intent(in) :: name
1503
type(attribute_t), pointer :: att
1507
if (associated(elem)) then
1508
do i = 1, size(elem%attlist%list)
1509
if (str_vs(elem%attlist%list(i)%name)==name) then
1510
att => elem%attlist%list(i)
1515
end function get_attdecl_by_name
1517
pure function express_att_decl_len(a) result(n)
1518
type(attribute_t), intent(in) :: a
1521
if (a%attType==ATT_ENUM) then
1524
n = size(a%name)+1+len_trim(ATT_TYPES(a%attType))
1527
if (a%attType==ATT_NOTATION &
1528
.or.a%attType==ATT_ENUM) &
1529
n = n + 1 + make_token_group_len(a%enumerations)
1531
select case(a%attDefault)
1533
n = n + len(" #REQUIRED")
1535
n = n + len(" #IMPLIED")
1539
n = n + len(" #FIXED")
1542
if (associated(a%default)) &
1543
n = n + 3 + size(a%default)
1544
end function express_att_decl_len
1546
function express_attribute_declaration(a) result(s)
1547
type(attribute_t), intent(in) :: a
1548
character(len=express_att_decl_len(a)) :: s
1550
if (a%attType==ATT_ENUM) then
1553
s = str_vs(a%name)//" "//ATT_TYPES(a%attType)
1555
if (a%attType==ATT_NOTATION &
1556
.or.a%attType==ATT_ENUM) &
1557
s = trim(s)//" "//make_token_group(a%enumerations)
1559
select case(a%attDefault)
1561
s = trim(s)//" #REQUIRED"
1563
s = trim(s)//" #IMPLIED"
1567
s = trim(s)//" #FIXED"
1570
if (associated(a%default)) &
1571
s = trim(s)//" """//str_vs(a%default)//""""
1572
end function express_attribute_declaration
1574
function get_att_type_enum(s) result(n)
1575
character(len=*), intent(in) :: s
1602
end function get_att_type_enum
1604
pure function att_value_normalize_len(s1) result(n)
1605
character(len=*), intent(in) :: s1
1614
if (w.and.(verify(s1(i:i),XML_WHITESPACE)==0)) cycle
1617
if (verify(s1(i:i),XML_WHITESPACE)==0) w = .true.
1619
if (w) n = n - 1 ! Discard final space
1621
end function att_value_normalize_len
1623
function att_value_normalize(s1) result(s2)
1624
character(len=*), intent(in) :: s1
1625
character(len=att_value_normalize_len(s1)) :: s2
1633
do while (i2<=len(s2))
1635
if (w.and.(verify(s1(i:i),XML_WHITESPACE)==0)) cycle
1639
if (verify(s1(i:i),XML_WHITESPACE)==0) w = .true.
1642
end function att_value_normalize
1645
end module m_common_element