-
Notifications
You must be signed in to change notification settings - Fork 25
/
testquery-noggeo.xq
511 lines (480 loc) · 27.6 KB
/
testquery-noggeo.xq
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
declare namespace act-core='http://inspire.ec.europa.eu/schemas/act-core/4.0';
declare namespace af='http://inspire.ec.europa.eu/schemas/af/4.0';
declare namespace bu-base='http://inspire.ec.europa.eu/schemas/bu-base/4.0';
declare namespace bu-core2d='http://inspire.ec.europa.eu/schemas/bu-core2d/4.0';
declare namespace hh='http://inspire.ec.europa.eu/schemas/hh/4.0';
declare namespace ef='http://inspire.ec.europa.eu/schemas/ef/4.0';
declare namespace mr-core='http://inspire.ec.europa.eu/schemas/mr-core/4.0';
declare namespace pf='http://inspire.ec.europa.eu/schemas/pf/4.0';
declare namespace nz-core ='http://inspire.ec.europa.eu/schemas/nz-core/4.0';
declare namespace elu='http://inspire.ec.europa.eu/schemas/elu/4.0';
declare namespace er-b='http://inspire.ec.europa.eu/schemas/er-b/4.0';
declare namespace er-c='http://inspire.ec.europa.eu/schemas/er-c/4.0';
declare namespace er-v='http://inspire.ec.europa.eu/schemas/er-v/4.0';
declare namespace gelu='http://inspire.ec.europa.eu/schemas/gelu/4.0';
declare namespace plu='http://inspire.ec.europa.eu/schemas/plu/4.0';
declare namespace selu='http://inspire.ec.europa.eu/schemas/selu/4.0';
declare namespace lunom='http://inspire.ec.europa.eu/schemas/lunom/4.0';
declare namespace am='http://inspire.ec.europa.eu/schemas/am/4.0';
declare namespace base2='http://inspire.ec.europa.eu/schemas/base2/2.0';
declare namespace au3='urn:x-inspire:specification:gmlas:AdministrativeUnits:3.0';
declare namespace ad3='urn:x-inspire:specification:gmlas:Addresses:3.0';
declare namespace cp3='urn:x-inspire:specification:gmlas:CadastralParcels:3.0';
declare namespace gn3='urn:x-inspire:specification:gmlas:GeographicalNames:3.0';
declare namespace hy3='urn:x-inspire:specification:gmlas:HydroBase:3.0';
declare namespace hy-n3='urn:x-inspire:specification:gmlas:HydroNetwork:3.0';
declare namespace hy-p3='urn:x-inspire:specification:gmlas:HydroPhysicalWaters:3.0';
declare namespace ps3='urn:x-inspire:specification:gmlas:ProtectedSites:3.0';
declare namespace tn3='urn:x-inspire:specification:gmlas:CommonTransportElements:3.0';
declare namespace tn-a3='urn:x-inspire:specification:gmlas:AirTransportNetwork:3.0';
declare namespace tn-c3='urn:x-inspire:specification:gmlas:CableTransportNetwork:3.0';
declare namespace tn-ra3='urn:x-inspire:specification:gmlas:RailwayTransportNetwork:3.0';
declare namespace tn-ro3='urn:x-inspire:specification:gmlas:RoadTransportNetwork:3.0';
declare namespace tn-w3='urn:x-inspire:specification:gmlas:WaterTransportNetwork:3.0';
declare namespace br='http://inspire.ec.europa.eu/schemas/br/4.0';
declare namespace bu-core3d3='http://inspire.jrc.ec.europa.eu/draft-schemas/bu-core3d/3.0';
declare namespace net3='urn:x-inspire:specification:gmlas:Network:3.2';
declare namespace base32='urn:x-inspire:specification:gmlas:BaseTypes:3.2';
declare namespace sd='http://inspire.ec.europa.eu/schemas/sd/4.0';
declare namespace hy='http://inspire.ec.europa.eu/schemas/hy/4.0';
declare namespace hy-n='http://inspire.ec.europa.eu/schemas/hy-n/4.0';
declare namespace hy-p='http://inspire.ec.europa.eu/schemas/hy-p/4.0';
declare namespace au='http://inspire.ec.europa.eu/schemas/au/4.0';
declare namespace ad='http://inspire.ec.europa.eu/schemas/ad/4.0';
declare namespace cp='http://inspire.ec.europa.eu/schemas/cp/4.0';
declare namespace el-cov='http://inspire.ec.europa.eu/schemas/el-cov/4.0';
declare namespace el-tin='http://inspire.ec.europa.eu/schemas/el-tin/4.0';
declare namespace el-vec='http://inspire.ec.europa.eu/schemas/el-vec/4.0';
declare namespace gn='http://inspire.ec.europa.eu/schemas/gn/4.0';
declare namespace ge='http://inspire.ec.europa.eu/schemas/ge-core/4.0';
declare namespace ge_gp='http://inspire.ec.europa.eu/schemas/ge_gp/4.0';
declare namespace ge_hg='http://inspire.ec.europa.eu/schemas/ge_hg/4.0';
declare namespace sams="http://www.opengis.net/samplingSpatial/2.0";
declare namespace lcn='http://inspire.ec.europa.eu/schemas/lcn/4.0';
declare namespace lcr='http://inspire.ec.europa.eu/schemas/lcr/4.0';
declare namespace lcv='http://inspire.ec.europa.eu/schemas/lcv/4.0';
declare namespace hb='http://inspire.ec.europa.eu/schemas/hb/4.0';
declare namespace mu='http://inspire.ec.europa.eu/schemas/mu/3.0';
declare namespace om='http://www.opengis.net/om/2.0';
declare namespace oi='http://inspire.ec.europa.eu/schemas/oi/4.0';
declare namespace omor='http://inspire.ec.europa.eu/schemas/omor/3.0';
declare namespace omso='http://inspire.ec.europa.eu/schemas/omso/3.0';
declare namespace pd='http://inspire.ec.europa.eu/schemas/pd/4.0';
declare namespace ps='http://inspire.ec.europa.eu/schemas/ps/4.0';
declare namespace sr='http://inspire.ec.europa.eu/schemas/sr/4.0';
declare namespace tn='http://inspire.ec.europa.eu/schemas/tn/4.0';
declare namespace tn-a='http://inspire.ec.europa.eu/schemas/tn-a/4.0';
declare namespace tn-c='http://inspire.ec.europa.eu/schemas/tn-c/4.0';
declare namespace tn-ra='http://inspire.ec.europa.eu/schemas/tn-ra/4.0';
declare namespace tn-ro='http://inspire.ec.europa.eu/schemas/tn-ro/4.0';
declare namespace tn-w='http://inspire.ec.europa.eu/schemas/tn-w/4.0';
declare namespace us-net-common='http://inspire.ec.europa.eu/schemas/us-net-common/4.0';
declare namespace us-net-el='http://inspire.ec.europa.eu/schemas/us-net-el/4.0';
declare namespace us-net-ogc='http://inspire.ec.europa.eu/schemas/us-net-ogc/4.0';
declare namespace us-net-sw='http://inspire.ec.europa.eu/schemas/us-net-sw/4.0';
declare namespace us-net-th='http://inspire.ec.europa.eu/schemas/us-net-th/4.0';
declare namespace us-net-wa='http://inspire.ec.europa.eu/schemas/us-net-wa/4.0';
declare namespace us-govserv='http://inspire.ec.europa.eu/schemas/us-govserv/4.0';
declare namespace us-emf='http://inspire.ec.europa.eu/schemas/us-emf/4.0';
declare namespace bu-core3d='http://inspire.ec.europa.eu/schemas/bu-core3d/4.0';
declare namespace net='http://inspire.ec.europa.eu/schemas/net/4.0';
declare namespace base='http://inspire.ec.europa.eu/schemas/base/3.3';
declare namespace gmd='http://www.isotc211.org/2005/gmd';
declare namespace gml='http://www.opengis.net/gml/3.2';
declare namespace wfs='http://www.opengis.net/wfs/2.0';
declare namespace xsi='http://www.w3.org/2001/XMLSchema-instance';
declare namespace xlink='http://www.w3.org/1999/xlink';
declare namespace etf='http://www.interactive-instruments.de/etf/2.0';
declare namespace atom='http://www.w3.org/2005/Atom';
declare namespace uuid='java.util.UUID';
import module namespace functx='http://www.functx.com';
import module namespace http='http://expath.org/ns/http-client';
declare variable $limitErrors external := 1000;
declare variable $validationErrors external := '';
declare variable $db external;
declare variable $features external;
declare variable $idMap external;
declare variable $testObjectId external;
declare variable $logFile external;
declare variable $statFile external;
declare function local:strippath($path as xs:string) as xs:string
{
let $sep := file:dir-separator()
return
if (contains($path,$sep)) then
local:strippath(substring-after($path,$sep))
else
replace($path,'\.[gGxX][mM][lL]','')
};
declare function local:filename($element as node()) as xs:string
{
db:path($element)
};
declare function local:log($text as xs:string) as empty-sequence()
{
let $dummy := file:append($logFile, $text || file:line-separator(), map { "method": "text", "media-type": "text/plain" })
return prof:dump($text)
};
declare function local:start($id as xs:string) as empty-sequence()
{
()
};
declare function local:end($id as xs:string, $status as xs:string) as empty-sequence()
{
()
};
declare function local:addMessage($templateId as xs:string, $map as map(*)) as element()
{
<message xmlns='http://www.interactive-instruments.de/etf/2.0' ref='{$templateId}'>
<translationArguments>
{ for $key in map:keys($map) return <argument token='{$key}'>{map:get($map,$key)}</argument> }
</translationArguments>
</message>
};
declare function local:passed($id as xs:string) as xs:boolean
{
true() (: TODO :)
};
declare function local:error-statistics($template as xs:string, $count as xs:integer) as element()*
{
(if ($count>=$limitErrors) then local:addMessage('TR.tooManyErrors', map { 'count': string($limitErrors) }) else (),
if ($count>0) then local:addMessage($template, map { 'count': string($count) }) else ())
};
declare function local:status($stati as xs:string*) as xs:string
{
if ($stati='FAILED') then 'FAILED' else if ($stati='SKIPPED') then 'SKIPPED' else if ($stati='WARNING') then 'WARNING' else if ($stati='INFO') then 'INFO' else if ($stati='PASSED_MANUAL') then 'PASSED_MANUAL' else if ($stati='PASSED') then 'PASSED' else if ($stati='NOT_APPLICABLE') then 'NOT_APPLICABLE' else 'UNDEFINED'
};
(: 'notHTTP' = not a HTTP(S) URL
'idNotFound' = a bare name Xpointer was provided, but not found
'EXCEPTION ...' = an exception occurred
HTTP status code = resource not available, the status code may point to the reason
media type = accessible :)
declare function local:check-resource-uri($uri as xs:string, $timeoutInS as xs:integer, $redirect as xs:boolean) as xs:string
{
if ($uri=('http://','https://')) then
'notHTTP'
else if (starts-with($uri,'http://') or starts-with($uri,'https://')) then
try {
let $loginfo := local:log('Checking URL: ''' || $uri || '''')
let $query := "import module namespace http = 'http://expath.org/ns/http-client'; declare variable $timeoutInS external; declare variable $redirect external; declare variable $uri external; http:send-request(<http:request method='get' timeout='{$timeoutInS}' status-only='true' follow-redirect='{$redirect}'/>, $uri)"
let $response := xquery:eval($query, map{ 'timeoutInS' : $timeoutInS, 'uri': $uri, 'redirect': $redirect }, map{ 'timeout': $timeoutInS })
return
if ($response/@status=('200','204')) then
let $contenttype := $response/http:header[lower-case(@name)='content-type']/@value
return
if ($contenttype) then $contenttype else 'application/octet-stream'
else if ($redirect and $response/@status=('301','302','303','307')) then
local:check-resource-uri($response/http:header[@name='Location']/@value, $timeoutInS, $redirect)
else
$response/@status
} catch *
{
let $logerror := local:log('Exception: ' || $err:description || ' URL: ' || $uri)
return 'EXCEPTION ' || $err:description
}
else if (starts-with($uri,'#')) then
if (map:contains($idMap,substring($uri,2))) then
'application/gml+xml'
else
'idNotFound'
else
'notHTTP'
};
declare function local:check-http-uris($uris as xs:string*, $timeoutInS as xs:integer, $max as xs:integer, $errors as xs:integer, $map as map(*), $redirect as xs:boolean) as map(*)
{
if (count($uris)=0) then $map
else if ($errors ge $limitErrors) then map:merge(( $map, for $uri in $uris return map{ $uri: 'SKIPPED' } )) (: too many errors already identified, skipping the remaining URIs :)
else
let $result := local:check-resource-uri($uris[1], $timeoutInS, $redirect)
let $newmap := map:merge( ($map, map{ $uris[1] : $result }) )
let $newerrors := if (matches($result,'(EXCEPTION|\d{3})')) then $errors+1 else $errors
return local:check-http-uris($uris[position() gt 1], $timeoutInS, $max, $newerrors, $newmap, $redirect)
};
declare function local:check-resource-uris($uris as xs:string*, $timeoutInS as xs:integer, $redirect as xs:boolean) as map(*)
{
let $remote := $uris[starts-with(.,'http://') or starts-with(.,'https://')]
let $local := $uris[starts-with(.,'#')]
return
map:merge((
local:check-http-uris($remote, $timeoutInS, count($remote), 0, map{}, $redirect),
for $uri in $local[map:contains($idMap,substring(.,2))] return map { $uri : 'application/gml+xml' },
for $uri in $local[not(map:contains($idMap,substring(.,2)))] return map { $uri : 'idNotFound' },
for $uri in $uris[not(starts-with(.,'#') or starts-with(.,'http://') or starts-with(.,'https://'))] return map { $uri : 'notHTTP' }
))
};
declare function local:check-feature-references($hrefs as node()*, $targets as xs:string*, $expected as xs:string, $property as xs:string) as element()*
{
local:check-feature-references($hrefs, $targets, $expected, $property, 0)
};
declare function local:check-feature-references($hrefs as node()*, $targets as xs:string*, $expected as xs:string, $property as xs:string, $level as xs:integer) as element()*
{
local:check-feature-references($hrefs, $targets, $expected, $property, $level, 'NONE')
};
declare function local:check-feature-references($hrefs as node()*, $targets as xs:string*, $expected as xs:string, $property as xs:string, $level as xs:integer, $specialCase as xs:string) as element()*
{
let $urls := fn:distinct-values($hrefs)
let $dummy := if (count($urls)>100) then local:log("Analyzing up to " || count($urls) || " feature references - this may take awhile...") else ()
let $map := local:check-resource-uris($urls, 30, false())
let $messages :=
(for $url at $pos in $urls
let $validuri := map:get($map, $url)
let $dummy := if ($pos mod 100 = 0) then local:log("Analyzing feature reference " || $pos || "/" || count($urls)) else ()
let $sourcefeatures := if ($level=1) then $hrefs[.=$url]/../../../..
else if ($level=2) then $hrefs[.=$url]/../../../../../..
else $hrefs[.=$url]/../..
return
if ($validuri = 'SKIPPED') then ()
else if ($validuri = 'notHTTP') then
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
return local:addMessage('TR.urlNotHttp2', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url })
else if ($validuri = 'idNotFound') then
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
return local:addMessage('TR.idNotFound2', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url })
else if (starts-with($validuri, 'EXCEPTION')) then
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
return local:addMessage('TR.resourceNotAccessibleExceptions2', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url, 'message': substring-after($validuri, 'EXCEPTION ') })
else if (matches($validuri,'\d{3}')) then
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
return local:addMessage('TR.resourceNotAccessible2', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url, 'status' : $validuri })
else if (starts-with($validuri,'text/xml') or starts-with($validuri,'application/gml+xml') or starts-with($validuri,'application/xml')) then
try {
let $root :=
if (starts-with($url,'#')) then map:get($idMap,substring($url,2))
else fn:doc($url)/element()
return
if ($specialCase='NONE' and local-name($root)=$targets) then ()
else if ($specialCase='formOfRoadNode' and local-name($root)='RoadServiceArea') then ()
else if ($specialCase='formOfRoadNode' and local-name($root)='RoadNode') then
if ($root[((tn-ro3:formOfRoadNode/text() eq 'roadServiceArea') or (tn-ro:formOfRoadNode/@xlink:href eq 'http://inspire.ec.europa.eu/codelist/FormOfRoadNodeValue/roadServiceArea'))]) then ()
else
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
let $v4 := fn:starts-with(namespace-uri($root/*:formOfRoadNode),'http://inspire.ec.europa.eu/schemas/')
let $value := if ($v4) then $root/tn-ro:formOfRoadNode/@xlink:href else $root/tn-ro3:formOfRoadNode/text()
return local:addMessage('TR.incorrectFormOfRoadNodeValue', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url, 'value': string($value) })
else
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
return local:addMessage('TR.unknownXMLResource2', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url, 'elementNameExpected': $expected, 'elementName': local-name($root), 'namespace': namespace-uri($root) })
} catch * {
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
return local:addMessage('TR.resourceNotAccessibleException2', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url, 'message': $err:description })
}
else
for $feature in $sourcefeatures
let $fid := string($feature/@gml:id)
return local:addMessage('TR.unknownResourceType2', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': $fid, 'property': $property, 'url': $url, 'mediaType': $validuri })
)[position() le $limitErrors]
return
(local:error-statistics('TR.featuresWithErrors', count(fn:distinct-values($messages//etf:argument[@token='gmlid']/text()))),
$messages)
};
declare function local:return-reference($href as node()) as element()?
{
try {
let $url := string($href)
let $root :=
if (starts-with($url,'#')) then map:get($idMap,substring($url,2))
else fn:doc($url)/element()
return $root
} catch * {
(: this is not for information accessibility checks, so we ignore 404s etc. :)
}
};
declare function local:return-references($urls as xs:string*) as map(*)
{
let $dummy := if (count($urls)>100) then local:log("Checking up to " || count($urls) || " references - this may take awhile...") else ()
return
map:merge( for $url at $pos in $urls
let $dummy := if ($pos mod 100 = 0) then local:log("Accessing reference " || $pos || "/" || count($urls)) else ()
return map { $url :
try {
let $root :=
if (starts-with($url,'#')) then map:get($idMap,substring($url,2))
else fn:doc($url)/element()
return $root
} catch * {
(: this is not for information accessibility checks, so we ignore 404s etc. :)
}
}
)
};
declare function local:check-code-list-values($objects3 as element()*, $objects4 as element()*, $property as xs:string, $uri as xs:string) as element()*
{
local:check-code-list-values($objects3, $objects4, $property, $uri, 0)
};
declare function local:check-code-list-values($objects3 as element()*, $objects4 as element()*, $property as xs:string, $uri as xs:string, $level as xs:integer) as element()*
{
let $clname := functx:substring-after-last-match($uri, 'http(s)?://inspire.ec.europa.eu/codelist/')
let $cluri := $uri || '/' || $clname || '.en.atom'
let $clfeed := if (fn:doc-available($cluri)) then fn:doc($cluri) else ()
return
if (not($clfeed)) then local:addMessage('TR.systemError', map { 'text': 'Code list ' || $uri || ' cannot be accessed.' })
else
let $normalizedUri := functx:substring-after-last-match($uri, 'http(s)?:')
let $normalizedValuesUri := for $valueUri in $clfeed//atom:entry/atom:id/text()
return functx:substring-after-last-match($valueUri, 'http(s)?:')
let $valuesCode := for $value in $normalizedValuesUri
return fn:substring-after($value, $normalizedUri || '/')
let $objectsWithErrors := ($objects3[*[local-name()=$property and not(@xsi:nil='true') and not(text()=$valuesCode)]] | $objects4[*[local-name()=$property and not(@xsi:nil='true') and not(functx:substring-after-last-match(@xlink:href, 'http(s)?:')=$normalizedValuesUri)]])[position() le $limitErrors]
let $featuresWithErrors :=
if ($level=1) then $objectsWithErrors/../..
else if ($level=2) then $objectsWithErrors/../../../..
else if ($level=3) then $objectsWithErrors/../../../../../..
else $objectsWithErrors
return
(local:error-statistics('TR.featuresWithErrors', count($featuresWithErrors)),
for $object in $objectsWithErrors
let $feature := if ($level=1) then $object/../..
else if ($level=2) then $object/../../../..
else if ($level=3) then $object/../../../../../..
else $object
order by $feature/@gml:id
for $prop in $object/*[local-name()=$property]
let $v4 := fn:starts-with(namespace-uri($prop),'http://inspire.ec.europa.eu/schemas/')
let $value := if ($v4) then $prop/@xlink:href else $prop/text()
return
local:addMessage('TR.disallowedCodeListValue', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': string($feature/@gml:id), 'property': $property, 'value': string($value), 'codelist' : $uri }))
};
(:
@throws: an error that explains why the code list could not be accessed
:)
declare function local:get-code-list-values($url as xs:string) as xs:string*
{
let $clname := functx:substring-after-last-match($url, 'http(s)?://inspire.ec.europa.eu/((metadata-)?codelist/)?')
let $clurl := $url || '/' || $clname || '.en.atom'
let $valid_clurl := try { local:check-resource-uri($clurl, 30, false()) } catch * { false() }
return
if ($valid_clurl = ('notHTTP','idNotFound') or matches($valid_clurl,'\d{3}')) then
error((),'Code list ' || $url || ' cannot be accessed.')
else if (starts-with($valid_clurl, 'EXCEPTION')) then
error((),'Access to code list ' || $url || ' failed or timed out.')
else if (not(starts-with($valid_clurl,'text/xml') or starts-with($valid_clurl,'application/xml') or starts-with($valid_clurl,'application/atom+xml'))) then
error((),'Unknown resource type encountered when accessing the atom representation of code list ' || $url || ' at URL ' || $clurl || '.')
else
try {
let $normalizedUrl := functx:substring-after-last-match($url, 'http(s)?:')
let $clfeed := fn:doc($clurl)
let $codeUris := $clfeed//atom:entry/atom:id/text()
let $codes := for $codeUri in $codeUris
let $normalizedCodeUri := functx:substring-after-last-match($codeUri, 'http(s)?:')
return fn:substring-after($normalizedCodeUri, $normalizedUrl || '/')
return
$codes
} catch * {
error((),'Code list ' || $url || ' cannot be accessed.')
}
};
(:
@throws: an error that explains why the code list could not be accessed
:)
declare function local:get-codes-in-atom-format($url as xs:string, $langId as xs:string) as element()*
{
let $clname := if (matches($url, 'http(s)?://inspire.ec.europa.eu/theme')) then 'theme' else functx:substring-after-last-match($url, 'http(s)?://inspire.ec.europa.eu/((metadata\-)?codelist/)?')
let $clurl := $url || '/' || $clname || '.' || $langId || '.atom'
let $valid_clurl := try { local:check-resource-uri($clurl, 30, false()) } catch * { false() }
return
if ($valid_clurl = ('notHTTP','idNotFound') or matches($valid_clurl,'\d{3}')) then
error((),'Code list ' || $url || ' cannot be accessed.')
else if (starts-with($valid_clurl, 'EXCEPTION')) then
error((),'Access to code list ' || $url || ' failed or timed out.')
else if (not(starts-with($valid_clurl,'text/xml') or starts-with($valid_clurl,'application/xml') or starts-with($valid_clurl,'application/atom+xml'))) then
error((),'Unknown resource type encountered when accessing the atom representation of code list ' || $url || ' at URL ' || $clurl || '.')
else
try {
let $root := fn:doc($clurl)/element()
return
$root//atom:entry
} catch * {
error((),'Code list ' || $url || ' cannot be accessed.')
}
};
(:
@throws: an error that explains why the invocation failed
:)
declare function local:get-code-titles($url as xs:string, $langIds as xs:string*) as xs:string*
{
let $codesAsAtomEntries := (
for $lang in $langIds
return
local:get-codes-in-atom-format($url,$lang)
)
return $codesAsAtomEntries/atom:title/text()
};
declare function local:is-valid-date-or-dateTime($dateString as xs:string?) as xs:boolean
{
if (not($dateString)) then
false()
else
let $date :=
try {
let $tmp := xs:date($dateString)
return
(: NOTE: apparently, the value of the xs:date must be evaluated to be parsed by BaseX :)
'DATE ' || $tmp
} catch * {
'INVALID'
}
let $dateTime :=
try {
let $tmp := xs:dateTime($dateString)
return
(: NOTE: apparently, the value of the xs:date must be evaluated to be parsed by BaseX :)
'DATETIME ' || $tmp
} catch * {
'INVALID'
}
return
if(starts-with($date,'DATE') or starts-with($dateTime,'DATETIME')) then
true()
else
false()
};
declare function local:testDesignationConstraint($features3 as element()*, $features4 as element()*, $scheme as xs:string, $codelist as xs:string ) as element()*
{
let $allowedValuesURI := local:getAllowedValuesURI( 'https://inspire.ec.europa.eu/codelist/' || $codelist )
let $allowedValuesCode := local:getAllowedValuesCode( $allowedValuesURI, $codelist )
let $valuesCode := fn:distinct-values($features3/ps3:siteDesignation/*[ps3:designationScheme=$scheme]/ps3:designation/text())
let $valuesURI := fn:distinct-values($features4/ps:siteDesignation/*[ps:designationScheme/@xlink:href=concat('https://inspire.ec.europa.eu/codelist/DesignationSchemeValue/',$scheme)]/ps:designation/@xlink:href)
let $badvaluesCode := functx:value-except($valuesCode,$allowedValuesCode)
let $badvaluesURI := functx:value-except($valuesURI,$allowedValuesURI)
let $featuresWithErrors3 := $features3[ps3:siteDesignation/*[ps3:designationScheme=$scheme]/ps3:designation/text()=$badvaluesCode]
let $featuresWithErrors4 := $features4[ps:siteDesignation/*[ps:designationScheme/@xlink:href=concat('https://inspire.ec.europa.eu/codelist/DesignationSchemeValue/',$scheme)]/ps:designation/@xlink:href=$badvaluesURI]
return
(for $feature in $featuresWithErrors3
order by $feature/@gml:id
let $values := $feature/ps3:siteDesignation/*[ps3:designationScheme=$scheme]/ps3:designation/text()[.=$badvaluesCode]
return
local:addMessage('TR.constraintViolation', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': string($feature/@gml:id), 'constraint': 'Sites must use designations from an appropriate designation scheme.', 'additionalInfo': 'For designation scheme ''' || $scheme || ''' the following disallowed value(s) have been used: ' || string-join($values,', ') || '. Allowed values are: ' || string-join($allowedValuesCode,', ') || '.' }),
for $feature in $featuresWithErrors4
order by $feature/@gml:id
let $values := $feature/ps:siteDesignation/*[ps:designationScheme/@xlink:href=concat('https://inspire.ec.europa.eu/codelist/DesignationSchemeValue/',$scheme)]/ps:designation/@xlink:href[.=$badvaluesURI]
return
local:addMessage('TR.constraintViolation', map { 'filename': local:filename($feature), 'featureType': local-name($feature), 'gmlid': string($feature/@gml:id), 'constraint': 'Sites must use designations from an appropriate designation scheme.', 'additionalInfo': 'For designation scheme ''' || $scheme || ''' the following disallowed value(s) have been used: ' || string-join($values,', ') || '. Allowed values are: ' || string-join($allowedValuesURI,', ') || '.' }))
};
declare function local:getAllowedValuesURI( $uri as xs:string ) as xs:string*
{
let $clname := functx:substring-after-last-match($uri, 'http(s)?://inspire.ec.europa.eu/codelist/')
let $cluri := $uri || '/' || $clname || '.en.atom'
let $clfeed := if (fn:doc-available($cluri)) then fn:doc($cluri) else ()
return
if (not($clfeed)) then
let $dummy := local:addMessage('TR.systemError', map { 'text': 'Code list ' || $uri || 'cannot be accessed.' })
return ()
else
let $valuesURI := $clfeed//atom:entry/atom:id/text()
return $valuesURI
};
declare function local:getAllowedValuesCode( $valuesURI as xs:string*, $uri as xs:string ) as xs:string*
{
let $valuesCode := for $value in $valuesURI return fn:substring-after($value, $uri || '/')
return $valuesCode
};
(: Start logging :)
let $logentry := local:log('Testing ' || count($features) || ' features')
(: Statistics and assertions follow below :)