standard_name_table.f90 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. !
  2. ! Fortran module to read standard_name_table XML files.
  3. !
  4. ! USAGE
  5. !
  6. ! use standard_name_table
  7. !
  8. ! type(T_Standard_Name_Table) :: xml_data
  9. !
  10. ! call standard_name_table_Init( xml_data, 'example.xml', status, lurep=5 )
  11. !
  12. ! call standard_name_table_Done( xml_data, status )
  13. !
  14. ! call standard_name_table_Write( xml_data, 'example-rewritten.xml', status, lurep=5 )
  15. !
  16. !
  17. ! HISTORY
  18. ! Code generated by the "xmlf-reader" program based on the free available
  19. ! "xml-fortran-1.00.tar.gz" package.
  20. ! Arjo Segers
  21. !
  22. ! 23 Oct 2012 - P. Le Sager - bug fix in standard_name_table_Init
  23. !
  24. module standard_name_table
  25. use XMLF
  26. implicit none
  27. integer, private :: lurep_
  28. logical, private :: strict_
  29. type T_CF_Entry
  30. character(len=256) :: id
  31. character(len=64) :: canonical_units
  32. character(len=16) :: grib
  33. end type T_CF_Entry
  34. type T_CF_Alias
  35. character(len=256) :: id
  36. character(len=256) :: entry_id
  37. end type T_CF_Alias
  38. type T_Standard_Name_Table
  39. integer :: version_number
  40. character(len=64) :: last_modified
  41. character(len=256) :: institution
  42. character(len=256) :: contact
  43. type(T_CF_Entry), dimension(:), pointer :: entry => null()
  44. type(T_CF_Alias), dimension(:), pointer :: alias => null()
  45. end type T_Standard_Name_Table
  46. contains
  47. ! =======================================================================
  48. ! ***
  49. subroutine read_xml_type_T_CF_Entry_array( &
  50. info, tag, endtag, attribs, noattribs, data, nodata, &
  51. dvar, has_dvar, status )
  52. type(XML_PARSE) :: info
  53. character(len=*), intent(inout) :: tag
  54. logical, intent(inout) :: endtag
  55. character(len=*), dimension(:,:), intent(inout) :: attribs
  56. integer, intent(inout) :: noattribs
  57. character(len=*), dimension(:), intent(inout) :: data
  58. integer, intent(inout) :: nodata
  59. type(T_CF_Entry), dimension(:), pointer :: dvar
  60. logical, intent(inout) :: has_dvar
  61. integer, intent(out) :: status
  62. integer :: newsize
  63. type(T_CF_Entry), dimension(:), pointer :: newvar
  64. newsize = size(dvar) + 1
  65. allocate( newvar(1:newsize) )
  66. newvar(1:newsize-1) = dvar
  67. deallocate( dvar )
  68. dvar => newvar
  69. call read_xml_type_T_CF_Entry( info, tag, endtag, attribs, noattribs, data, nodata, &
  70. dvar(newsize), has_dvar, status )
  71. end subroutine read_xml_type_T_CF_Entry_array
  72. ! ***
  73. subroutine read_xml_type_T_CF_Entry( info, starttag, endtag, attribs, noattribs, data, nodata, &
  74. dvar, has_dvar, status )
  75. type(XML_PARSE) :: info
  76. character(len=*), intent(in) :: starttag
  77. logical, intent(inout) :: endtag
  78. character(len=*), dimension(:,:), intent(inout) :: attribs
  79. integer, intent(inout) :: noattribs
  80. character(len=*), dimension(:), intent(inout) :: data
  81. integer, intent(inout) :: nodata
  82. type(T_CF_Entry), intent(inout) :: dvar
  83. logical, intent(inout) :: has_dvar
  84. integer, intent(out) :: status
  85. integer :: att_
  86. integer :: noatt_
  87. logical :: error
  88. logical :: endtag_org
  89. character(len=80) :: tag
  90. logical :: has_id
  91. logical :: has_canonical_units
  92. logical :: has_grib
  93. has_id = .false.
  94. has_canonical_units = .false.
  95. has_grib = .false.
  96. call init_xml_type_T_CF_Entry(dvar)
  97. has_dvar = .true.
  98. error = .false.
  99. att_ = 0
  100. noatt_ = noattribs+1
  101. endtag_org = endtag
  102. do
  103. if ( nodata .ne. 0 ) then
  104. noattribs = 0
  105. tag = starttag
  106. elseif ( att_ .lt. noatt_ .and. noatt_ .gt. 1 ) then
  107. att_ = att_ + 1
  108. if ( att_ .le. noatt_-1 ) then
  109. tag = attribs(1,att_)
  110. data(1) = attribs(2,att_)
  111. noattribs = 0
  112. nodata = 1
  113. endtag = .false.
  114. else
  115. tag = starttag
  116. noattribs = 0
  117. nodata = 0
  118. endtag = .true.
  119. cycle
  120. endif
  121. else
  122. if ( endtag_org ) then
  123. return
  124. else
  125. call xml_get( info, tag, endtag, attribs, noattribs, data, nodata )
  126. if ( xml_error(info) ) then
  127. write(lurep_,*) 'Error reading input file!'
  128. error = .true.
  129. status=1; return
  130. endif
  131. endif
  132. endif
  133. if ( endtag .and. tag .eq. starttag ) then
  134. exit
  135. endif
  136. if ( endtag .and. noattribs .eq. 0 ) then
  137. if ( xml_ok(info) ) then
  138. cycle
  139. else
  140. exit
  141. endif
  142. endif
  143. select case( tag )
  144. case('id')
  145. call read_xml_line( &
  146. info, tag, endtag, attribs, noattribs, data, nodata, &
  147. dvar%id, has_id, status )
  148. case('canonical_units')
  149. call read_xml_line( &
  150. info, tag, endtag, attribs, noattribs, data, nodata, &
  151. dvar%canonical_units, has_canonical_units, status )
  152. case('grib')
  153. call read_xml_line( &
  154. info, tag, endtag, attribs, noattribs, data, nodata, &
  155. dvar%grib, has_grib, status )
  156. case ('comment', '!--')
  157. ! Simply ignore
  158. case default
  159. if ( strict_ ) then
  160. error = .true.
  161. call xml_report_errors( info, &
  162. 'Unknown or wrongly placed tag: ' // trim(tag))
  163. endif
  164. end select
  165. nodata = 0
  166. if ( .not. xml_ok(info) ) exit
  167. end do
  168. if ( .not. has_id ) then
  169. has_dvar = .false.
  170. call xml_report_errors(info, 'Missing data on id')
  171. endif
  172. if ( .not. has_canonical_units ) then
  173. has_dvar = .false.
  174. call xml_report_errors(info, 'Missing data on canonical_units')
  175. endif
  176. end subroutine read_xml_type_T_CF_Entry
  177. ! ***
  178. subroutine init_xml_type_T_CF_Entry_array( dvar )
  179. type(T_CF_Entry), dimension(:), pointer :: dvar
  180. if ( associated( dvar ) ) then
  181. deallocate( dvar )
  182. endif
  183. allocate( dvar(0) )
  184. end subroutine init_xml_type_T_CF_Entry_array
  185. ! ***
  186. subroutine init_xml_type_T_CF_Entry(dvar)
  187. type(T_CF_Entry) :: dvar
  188. dvar%grib = ''
  189. end subroutine init_xml_type_T_CF_Entry
  190. ! ***
  191. subroutine write_xml_type_T_CF_Entry_array( &
  192. info, tag, indent, dvar )
  193. type(XML_PARSE) :: info
  194. character(len=*), intent(in) :: tag
  195. integer :: indent
  196. type(T_CF_Entry), dimension(:) :: dvar
  197. integer :: i
  198. do i = 1,size(dvar)
  199. call write_xml_type_T_CF_Entry( info, tag, indent, dvar(i) )
  200. enddo
  201. end subroutine write_xml_type_T_CF_Entry_array
  202. ! ***
  203. subroutine write_xml_type_T_CF_Entry( &
  204. info, tag, indent, dvar )
  205. type(XML_PARSE) :: info
  206. character(len=*), intent(in) :: tag
  207. integer :: indent
  208. type(T_CF_Entry) :: dvar
  209. character(len=100) :: indentation
  210. indentation = ' '
  211. write(info%lun, '(4a)' ) indentation(1:min(indent,100)),&
  212. '<',trim(tag), '>'
  213. call write_to_xml_line( info, 'id', indent+3, dvar%id)
  214. call write_to_xml_line( info, 'canonical_units', indent+3, dvar%canonical_units)
  215. call write_to_xml_line( info, 'grib', indent+3, dvar%grib)
  216. write(info%lun,'(4a)') indentation(1:min(indent,100)), &
  217. '</' //trim(tag) // '>'
  218. end subroutine write_xml_type_T_CF_Entry
  219. ! ***
  220. subroutine read_xml_type_T_CF_Alias_array( &
  221. info, tag, endtag, attribs, noattribs, data, nodata, &
  222. dvar, has_dvar, status )
  223. type(XML_PARSE) :: info
  224. character(len=*), intent(inout) :: tag
  225. logical, intent(inout) :: endtag
  226. character(len=*), dimension(:,:), intent(inout) :: attribs
  227. integer, intent(inout) :: noattribs
  228. character(len=*), dimension(:), intent(inout) :: data
  229. integer, intent(inout) :: nodata
  230. type(T_CF_Alias), dimension(:), pointer :: dvar
  231. logical, intent(inout) :: has_dvar
  232. integer, intent(out) :: status
  233. integer :: newsize
  234. type(T_CF_Alias), dimension(:), pointer :: newvar
  235. newsize = size(dvar) + 1
  236. allocate( newvar(1:newsize) )
  237. newvar(1:newsize-1) = dvar
  238. deallocate( dvar )
  239. dvar => newvar
  240. call read_xml_type_T_CF_Alias( info, tag, endtag, attribs, noattribs, data, nodata, &
  241. dvar(newsize), has_dvar, status )
  242. end subroutine read_xml_type_T_CF_Alias_array
  243. ! ***
  244. subroutine read_xml_type_T_CF_Alias( info, starttag, endtag, attribs, noattribs, data, nodata, &
  245. dvar, has_dvar, status )
  246. type(XML_PARSE) :: info
  247. character(len=*), intent(in) :: starttag
  248. logical, intent(inout) :: endtag
  249. character(len=*), dimension(:,:), intent(inout) :: attribs
  250. integer, intent(inout) :: noattribs
  251. character(len=*), dimension(:), intent(inout) :: data
  252. integer, intent(inout) :: nodata
  253. type(T_CF_Alias), intent(inout) :: dvar
  254. logical, intent(inout) :: has_dvar
  255. integer, intent(out) :: status
  256. integer :: att_
  257. integer :: noatt_
  258. logical :: error
  259. logical :: endtag_org
  260. character(len=80) :: tag
  261. logical :: has_id
  262. logical :: has_entry_id
  263. has_id = .false.
  264. has_entry_id = .false.
  265. call init_xml_type_T_CF_Alias(dvar)
  266. has_dvar = .true.
  267. error = .false.
  268. att_ = 0
  269. noatt_ = noattribs+1
  270. endtag_org = endtag
  271. do
  272. if ( nodata .ne. 0 ) then
  273. noattribs = 0
  274. tag = starttag
  275. elseif ( att_ .lt. noatt_ .and. noatt_ .gt. 1 ) then
  276. att_ = att_ + 1
  277. if ( att_ .le. noatt_-1 ) then
  278. tag = attribs(1,att_)
  279. data(1) = attribs(2,att_)
  280. noattribs = 0
  281. nodata = 1
  282. endtag = .false.
  283. else
  284. tag = starttag
  285. noattribs = 0
  286. nodata = 0
  287. endtag = .true.
  288. cycle
  289. endif
  290. else
  291. if ( endtag_org ) then
  292. return
  293. else
  294. call xml_get( info, tag, endtag, attribs, noattribs, data, nodata )
  295. if ( xml_error(info) ) then
  296. write(lurep_,*) 'Error reading input file!'
  297. error = .true.
  298. status=1; return
  299. endif
  300. endif
  301. endif
  302. if ( endtag .and. tag .eq. starttag ) then
  303. exit
  304. endif
  305. if ( endtag .and. noattribs .eq. 0 ) then
  306. if ( xml_ok(info) ) then
  307. cycle
  308. else
  309. exit
  310. endif
  311. endif
  312. select case( tag )
  313. case('id')
  314. call read_xml_line( &
  315. info, tag, endtag, attribs, noattribs, data, nodata, &
  316. dvar%id, has_id, status )
  317. case('entry_id')
  318. call read_xml_line( &
  319. info, tag, endtag, attribs, noattribs, data, nodata, &
  320. dvar%entry_id, has_entry_id, status )
  321. case ('comment', '!--')
  322. ! Simply ignore
  323. case default
  324. if ( strict_ ) then
  325. error = .true.
  326. call xml_report_errors( info, &
  327. 'Unknown or wrongly placed tag: ' // trim(tag))
  328. endif
  329. end select
  330. nodata = 0
  331. if ( .not. xml_ok(info) ) exit
  332. end do
  333. if ( .not. has_id ) then
  334. has_dvar = .false.
  335. call xml_report_errors(info, 'Missing data on id')
  336. endif
  337. if ( .not. has_entry_id ) then
  338. has_dvar = .false.
  339. call xml_report_errors(info, 'Missing data on entry_id')
  340. endif
  341. end subroutine read_xml_type_T_CF_Alias
  342. ! ***
  343. subroutine init_xml_type_T_CF_Alias_array( dvar )
  344. type(T_CF_Alias), dimension(:), pointer :: dvar
  345. if ( associated( dvar ) ) then
  346. deallocate( dvar )
  347. endif
  348. allocate( dvar(0) )
  349. end subroutine init_xml_type_T_CF_Alias_array
  350. ! ***
  351. subroutine init_xml_type_T_CF_Alias(dvar)
  352. type(T_CF_Alias) :: dvar
  353. end subroutine init_xml_type_T_CF_Alias
  354. ! ***
  355. subroutine write_xml_type_T_CF_Alias_array( &
  356. info, tag, indent, dvar )
  357. type(XML_PARSE) :: info
  358. character(len=*), intent(in) :: tag
  359. integer :: indent
  360. type(T_CF_Alias), dimension(:) :: dvar
  361. integer :: i
  362. do i = 1,size(dvar)
  363. call write_xml_type_T_CF_Alias( info, tag, indent, dvar(i) )
  364. enddo
  365. end subroutine write_xml_type_T_CF_Alias_array
  366. ! ***
  367. subroutine write_xml_type_T_CF_Alias( &
  368. info, tag, indent, dvar )
  369. type(XML_PARSE) :: info
  370. character(len=*), intent(in) :: tag
  371. integer :: indent
  372. type(T_CF_Alias) :: dvar
  373. character(len=100) :: indentation
  374. indentation = ' '
  375. write(info%lun, '(4a)' ) indentation(1:min(indent,100)),&
  376. '<',trim(tag), '>'
  377. call write_to_xml_line( info, 'id', indent+3, dvar%id)
  378. call write_to_xml_line( info, 'entry_id', indent+3, dvar%entry_id)
  379. write(info%lun,'(4a)') indentation(1:min(indent,100)), &
  380. '</' //trim(tag) // '>'
  381. end subroutine write_xml_type_T_CF_Alias
  382. ! ***
  383. subroutine standard_name_table_Init( gvar, fname, status, lurep )
  384. ! --- in/out ---------------------------------------------------
  385. type(T_Standard_Name_Table), intent(out) :: gvar
  386. character(len=*), intent(in) :: fname
  387. integer, intent(out) :: status
  388. integer, intent(in), optional :: lurep
  389. ! --- local ---------------------------------------------------
  390. type(XML_PARSE) :: info
  391. logical :: error
  392. character(len=80) :: tag
  393. character(len=80) :: starttag
  394. logical :: endtag
  395. character(len=80), dimension(1:2,1:20) :: attribs
  396. integer :: noattribs
  397. character(len=200), dimension(1:100) :: data
  398. integer :: nodata
  399. logical :: has_version_number
  400. logical :: has_last_modified
  401. logical :: has_institution
  402. logical :: has_contact
  403. logical :: has_entry
  404. logical :: has_alias
  405. has_version_number = .false.
  406. has_last_modified = .false.
  407. has_institution = .false.
  408. has_contact = .false.
  409. has_entry = .false.
  410. allocate(gvar%entry(0))
  411. has_alias = .false.
  412. allocate(gvar%alias(0))
  413. call init_xml_file_standard_name_table()
  414. ! Prior 23-10-2012 (PLS: moved below, after xml_open to avoid bad initialization)
  415. ! call xml_options( info, report_errors=.true., ignore_whitespace=.true.)
  416. ! if (info%error) then; status=1; return; end if
  417. call xml_open( info, fname, .true. )
  418. if (info%error) then; status=1; return; end if
  419. ! After 23-10-2012 (PLS: moved here, after xml_open to avoid bad initialization)
  420. call xml_options( info, report_errors=.true., ignore_whitespace=.true.)
  421. if (info%error) then; status=1; return; end if
  422. lurep_ = 0
  423. if ( present(lurep) ) then
  424. lurep_ = lurep
  425. call xml_options( info, report_lun=lurep )
  426. endif
  427. do
  428. call xml_get( info, starttag, endtag, attribs, noattribs, &
  429. data, nodata)
  430. if ( starttag .ne. '!--' ) exit
  431. enddo
  432. if ( starttag .ne. "standard_name_table" ) then
  433. call xml_report_errors( info, &
  434. 'XML-file should have root element "standard_name_table"')
  435. error = .true.
  436. call xml_close(info)
  437. status=1; return
  438. endif
  439. strict_ = .false.
  440. error = .false.
  441. do
  442. call xml_get( info, tag, endtag, attribs, noattribs, data, nodata )
  443. if ( xml_error(info) ) then
  444. write(lurep_,*) 'Error reading input file!'
  445. error = .true.
  446. status=1; return
  447. endif
  448. if ( endtag .and. tag .eq. starttag ) then
  449. exit
  450. endif
  451. if ( endtag .and. noattribs .eq. 0 ) then
  452. if ( xml_ok(info) ) then
  453. cycle
  454. else
  455. exit
  456. endif
  457. endif
  458. select case( tag )
  459. case('version_number')
  460. call read_xml_integer( &
  461. info, tag, endtag, attribs, noattribs, data, nodata, &
  462. gvar%version_number, has_version_number, status )
  463. case('last_modified')
  464. call read_xml_line( &
  465. info, tag, endtag, attribs, noattribs, data, nodata, &
  466. gvar%last_modified, has_last_modified, status )
  467. case('institution')
  468. call read_xml_line( &
  469. info, tag, endtag, attribs, noattribs, data, nodata, &
  470. gvar%institution, has_institution, status )
  471. case('contact')
  472. call read_xml_line( &
  473. info, tag, endtag, attribs, noattribs, data, nodata, &
  474. gvar%contact, has_contact, status )
  475. case('entry')
  476. call read_xml_type_T_CF_Entry_array( &
  477. info, tag, endtag, attribs, noattribs, data, nodata, &
  478. gvar%entry, has_entry, status )
  479. case('alias')
  480. call read_xml_type_T_CF_Alias_array( &
  481. info, tag, endtag, attribs, noattribs, data, nodata, &
  482. gvar%alias, has_alias, status )
  483. case ('comment', '!--')
  484. ! Simply ignore
  485. case default
  486. if ( strict_ ) then
  487. error = .true.
  488. call xml_report_errors( info, &
  489. 'Unknown or wrongly placed tag: ' // trim(tag))
  490. endif
  491. end select
  492. nodata = 0
  493. if ( .not. xml_ok(info) ) exit
  494. end do
  495. if ( .not. has_version_number ) then
  496. error = .true.
  497. call xml_report_errors(info, 'Missing data on version_number')
  498. endif
  499. if ( .not. has_last_modified ) then
  500. error = .true.
  501. call xml_report_errors(info, 'Missing data on last_modified')
  502. endif
  503. if ( .not. has_institution ) then
  504. error = .true.
  505. call xml_report_errors(info, 'Missing data on institution')
  506. endif
  507. if ( .not. has_contact ) then
  508. error = .true.
  509. call xml_report_errors(info, 'Missing data on contact')
  510. endif
  511. if ( .not. has_entry ) then
  512. error = .true.
  513. call xml_report_errors(info, 'Missing data on entry')
  514. endif
  515. if ( .not. has_alias ) then
  516. error = .true.
  517. call xml_report_errors(info, 'Missing data on alias')
  518. endif
  519. ! set return code:
  520. status = 0
  521. if ( error ) status = -1
  522. end subroutine
  523. ! ***
  524. subroutine standard_name_table_Done( gvar, status )
  525. ! --- in/out ---------------------------------------------------
  526. type(T_Standard_Name_Table), intent(inout) :: gvar
  527. integer, intent(out) :: status
  528. ! --- local ---------------------------------------------------
  529. if ( associated(gvar%entry) ) deallocate( gvar%entry )
  530. if ( associated(gvar%alias) ) deallocate( gvar%alias )
  531. ! ok:
  532. status = 0
  533. end subroutine
  534. ! ***
  535. subroutine standard_name_table_Write( gvar, fname, status, lurep )
  536. ! --- in/out ---------------------------------------------------
  537. type(T_Standard_Name_Table), intent(in) :: gvar
  538. character(len=*), intent(in) :: fname
  539. integer, intent(out) :: status
  540. integer, intent(in), optional :: lurep
  541. ! --- local ---------------------------------------------------
  542. type(XML_PARSE) :: info
  543. integer :: indent = 0
  544. ! --- in/out ---------------------------------------------------
  545. call xml_open( info, fname, .false. )
  546. call xml_options( info, report_errors=.true.)
  547. if ( present(lurep) ) then
  548. call xml_options( info, report_errors=.true.)
  549. endif
  550. write(info%lun,'(a)') &
  551. '<standard_name_table>'
  552. call write_to_xml_integer( info, 'version_number', indent+3, gvar%version_number)
  553. call write_to_xml_line( info, 'last_modified', indent+3, gvar%last_modified)
  554. call write_to_xml_line( info, 'institution', indent+3, gvar%institution)
  555. call write_to_xml_line( info, 'contact', indent+3, gvar%contact)
  556. call write_xml_type_T_CF_Entry_array( info, 'entry', indent+3, gvar%entry)
  557. call write_xml_type_T_CF_Alias_array( info, 'alias', indent+3, gvar%alias)
  558. write(info%lun,'(a)') '</standard_name_table>'
  559. call xml_close(info)
  560. ! ok
  561. status = 0
  562. end subroutine
  563. ! ***
  564. subroutine init_xml_file_standard_name_table
  565. end subroutine
  566. end module