Skip to content

Commit 224c118

Browse files
authored
Update schema (rnc) and schematron (sch) to support map-a (#214)
1 parent 1d6aa01 commit 224c118

File tree

2 files changed

+66
-62
lines changed

2 files changed

+66
-62
lines changed

schema/mapml.rnc

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ body = element body { bodyContent }
3333
bodyContent = extent? & links & (feature | tile | image)*
3434
extent = element extent {
3535
attribute units { "OSMTILE" | "CBMTILE" | "APSTILE" | "WGS84" }?,
36-
attribute action { xsd:anyURI }?,
37-
attribute method { "get" | "GET" }?,
38-
attribute enctype { "application/x-www-form-urlencoded" }?,
3936
(inputs* & datalist* & links* & select* & label*)?
4037
}
4138
inputs = (element input {
@@ -51,10 +48,10 @@ inputs = (element input {
5148
# https://developer.mozilla.org/en-US/docs/Web/CSS/object-position
5249
attribute position { "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center-left" | "center-right" | "top-center" | "bottom-center" | "center" }?,
5350
attribute axis { "latitude" | "longitude" | "easting" | "northing" | "x" | "y" | "row" | "column" | "i" | "j" }?,
54-
attribute units {"tilematrix" | "pcrs" | "tcrs" | "map" | "gcrs" | "tile" }?,
51+
attribute units {"gcrs" | "pcrs" | "tcrs" | "map" | "tilematrix" | "tile" }?,
5552
attribute required { xsd:boolean }?,
56-
attribute min { xsd:decimal }?,
57-
attribute max { xsd:decimal }?,
53+
attribute min { xsd:double }?,
54+
attribute max { xsd:double }?,
5855
attribute step { text }?
5956
})
6057
datalist = element datalist {
@@ -88,7 +85,11 @@ tile = element tile {
8885
}
8986
bbox = element bbox { twoPositions }
9087
image = element image { ImageModel }
91-
geometry = element geometry { GeometryContent }
88+
89+
geometry = element geometry {
90+
attribute cs { "gcrs" | "pcrs" | "tcrs" | "map" | "tilematrix" | "tile" }?,
91+
(GeometryContent | map-a)
92+
}
9293
properties = element properties { PropertyContent }
9394
featurecaption = element featurecaption { text? }
9495

@@ -107,23 +108,28 @@ any_attribute = attribute * { text }
107108
imageLocation = attribute x { xsd:double }, attribute y { xsd:double }
108109
imageSize = attribute width { xsd:integer },attribute height { xsd:integer }
109110

110-
GeometryContent = point | linestring | polygon | multipoint | multilinestring | multipolygon | geometrycollection
111-
point = element point { coordinates_mixed }
112-
linestring = element linestring { coordinates_mixed }
113-
polygon = element polygon { coordinates_mixed+ }
114-
multipoint = element multipoint { coordinates_mixed }
115-
multilinestring = element multilinestring { coordinates_mixed+ }
116-
multipolygon = element multipolygon { polygon+ }
111+
GeometryContent = point | linestring | polygon | multipoint | multilinestring | multipolygon | geometrycollection
112+
map-a = element map-a {
113+
attribute href { text },
114+
attribute target { "_self" | "_top" | "_blank" | "_parent" }?,
115+
attribute type { "text/mapml" | "text/html" }?,
116+
(GeometryContent | text | span_element | coordinates_mixed)}
117+
point = element point { map-a | coordinates_mixed }
118+
linestring = element linestring { map-a | coordinates_mixed }
119+
polygon = element polygon { map-a* & coordinates_mixed+ }
120+
multipoint = element multipoint { map-a | coordinates_mixed }
121+
multilinestring = element multilinestring { map-a* & coordinates_mixed+ }
122+
multipolygon = element multipolygon { map-a* & polygon+ }
117123
geometrycollection = element geometrycollection {
118124
(point* & linestring* & polygon* & multipoint* & multilinestring* & multipolygon*)
119125
}
120-
# TODO: allow either span OR a, and possibly others.
121126
span_element = element span {
122127
mixed {
123128
attribute * { text }*&
124-
span_element*
129+
span_element* &
130+
map-a*
125131
}
126132
}
127-
coordinates_mixed = element coordinates { mixed { span_element* } }
133+
coordinates_mixed = element coordinates { mixed { span_element* & map-a* } }
128134
# for bbox content, omits coordinates element
129135
twoPositions = list { (xsd:double, xsd:double, xsd:double, xsd:double) }

schema/mapml.sch

Lines changed: 43 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,112 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2"
3-
xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:xs="http://www.w3.org/2001/XMLSchema-datatypes" >
4-
<sch:pattern >
5-
<sch:rule context="input[@type='location'][@units eq 'tilematrix'][@axis eq 'row' or @axis eq 'column']">
2+
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2"
3+
xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:xs="http://www.w3.org/2001/XMLSchema-datatypes" xmlns="http://www.w3.org/1999/xhtml">
4+
<sch:ns uri="http://www.w3.org/1999/xhtml" prefix="h"/>
5+
<sch:pattern >
6+
<sch:rule context="h:input[@type='location'][@units eq 'tilematrix'][@axis eq 'row' or @axis eq 'column']">
67
<sch:assert test="./@rel eq 'map' or not(./@rel)">For inputs[@type=location], @rel must equal 'map' or not exist</sch:assert>
78
</sch:rule>
8-
<sch:rule context="input[@type='location'][@units eq 'map']">
9+
<sch:rule context="h:input[@type='location'][@units eq 'map']">
910
<sch:assert test="./@axis eq 'j' or ./@axis eq 'i'">For inputs[@type=location][units=map] @axis must exist and be equal to either i or j</sch:assert>
1011
</sch:rule>
11-
<sch:rule context="input[@type='location'][@axis eq 'easting']">
12-
<sch:assert test="exists(preceding-sibling::input[@axis eq 'northing']) or exists(following-sibling::input[@axis eq 'northing'])">Easting axis reference must have paired northing axis reference</sch:assert>
12+
<sch:rule context="h:input[@type='location'][@axis eq 'easting']">
13+
<sch:assert test="exists(preceding-sibling::h:input[@axis eq 'northing']) or exists(following-sibling::h:input[@axis eq 'northing'])">Easting axis reference must have paired northing axis reference</sch:assert>
1314
</sch:rule>
14-
<sch:rule context="input[@type='location'][@axis eq 'northing']">
15-
<sch:assert test="exists(preceding-sibling::input[@axis eq 'easting']) or exists(following-sibling::input[@axis eq 'easting'])">Northing axis reference must have paired easting axis reference</sch:assert>
15+
<sch:rule context="h:input[@type='location'][@axis eq 'northing']">
16+
<sch:assert test="exists(preceding-sibling::h:input[@axis eq 'easting']) or exists(following-sibling::h:input[@axis eq 'easting'])">Northing axis reference must have paired easting axis reference</sch:assert>
1617
</sch:rule>
17-
<sch:rule context="input[@type='hidden'][@shard]">
18+
<sch:rule context="h:input[@type='hidden'][@shard]">
1819
<sch:assert test="exists(./@list)">A shard-type input must have a @list attribute</sch:assert>
1920
<sch:let name="listid" value="./@list"></sch:let>
20-
<sch:assert test="exists(//datalist[@id eq $listid])">A datalist must be associated to a shard-type input</sch:assert>
21+
<sch:assert test="exists(//h:datalist[@id eq $listid])">A datalist must be associated to a shard-type input</sch:assert>
2122
<sch:report test="exists(./@value)">A shard-type input must not have a @value</sch:report>
2223
</sch:rule>
23-
<sch:rule context="input[@shard]">
24+
<sch:rule context="h:input[@shard]">
2425
<sch:assert test=".[@type eq 'hidden']">A shard-type input must have @type="hidden"</sch:assert>
2526
</sch:rule>
26-
<sch:rule context="extent">
27-
<sch:assert test="input[@type eq 'zoom']">Extent must have a zoom input</sch:assert>
28-
<sch:assert test="(count((input[@type='location'][@axis eq 'i'] union input[@type='location'][@axis eq 'j'])) mod 2) eq 0">location inputs with axis=i or j must come in pairs</sch:assert>
29-
<sch:assert test="(count(input[@type='location'][@axis eq 'easting' or @axis eq 'northing']) mod 2) eq 0">location inputs with axis=easting or northing must come in pairs</sch:assert>
30-
<sch:assert test="(count(input[@type='location'][@axis eq 'latitude' or @axis eq 'longitude']) mod 2) eq 0">location inputs with axis=latitude or longitude must come in pairs</sch:assert>
31-
<sch:assert test="(count(input[@type='location'][@axis eq 'row' or @axis eq 'column']) mod 2) eq 0">location inputs with axis=row or column must come in pairs</sch:assert>
32-
<sch:assert test="(count(input[@type='location'][@axis eq 'x' or @axis eq 'y']) mod 2) eq 0">location inputs with axis=x or y must come in pairs</sch:assert>
33-
<sch:report test="(exists(@method) and not(exists(@action)))">An extent with a method attribute must have an action attribute</sch:report>
27+
<sch:rule context="h:extent">
28+
<sch:assert test="h:input[@type eq 'zoom']">Extent must have a zoom input</sch:assert>
29+
<sch:assert test="(count((h:input[@type='location'][@axis eq 'i'] union h:input[@type='location'][@axis eq 'j'])) mod 2) eq 0">location inputs with axis=i or j must come in pairs</sch:assert>
30+
<sch:assert test="(count(h:input[@type='location'][@axis eq 'easting' or @axis eq 'northing']) mod 2) eq 0">location inputs with axis=easting or northing must come in pairs</sch:assert>
31+
<sch:assert test="(count(h:input[@type='location'][@axis eq 'latitude' or @axis eq 'longitude']) mod 2) eq 0">location inputs with axis=latitude or longitude must come in pairs</sch:assert>
32+
<sch:assert test="(count(h:input[@type='location'][@axis eq 'row' or @axis eq 'column']) mod 2) eq 0">location inputs with axis=row or column must come in pairs</sch:assert>
33+
<sch:assert test="(count(h:input[@type='location'][@axis eq 'x' or @axis eq 'y']) mod 2) eq 0">location inputs with axis=x or y must come in pairs</sch:assert>
3434
</sch:rule>
3535
</sch:pattern>
3636
<sch:pattern>
37-
<sch:rule context="extent[@action]">
38-
<sch:assert test="input and (count(link[@rel='query']) eq 1 or not(exists(link[@rel='query'])))"> Extent Content model: If the action attribute exists: A set of multiple input and zero or one link element with its rel attribute in the "query" state.</sch:assert>
39-
</sch:rule>
40-
<sch:rule context="extent[not(@action)]">
41-
<sch:assert test="input and link[@rel=('tile','image','features')] and count(link[@rel eq 'query']) &lt;= 1"> Extent Content model: If no action attribute exists: A set of multiple input and one or more link elements with their rel attribute in either the "tile", "image" or "features" state, and zero or one link element with its rel attribute in the "query" state.</sch:assert>
37+
<sch:rule context="h:extent">
38+
<sch:assert test="h:input and h:link[@rel=('tile','image','features')] and count(h:link[@rel eq 'query']) &lt;= 1"> Extent Content model: A set of multiple input and one or more link elements with their rel attribute in either the "tile", "image" or "features" state, and zero or one link element with its rel attribute in the "query" state.</sch:assert>
4239
</sch:rule>
4340
</sch:pattern>
4441
<sch:pattern>
45-
<sch:rule context="head/link">
42+
<sch:rule context="h:head/h:link">
4643
<sch:assert test="exists(@href)">Links in head should have a href attribute (head links should not be templated).</sch:assert>
4744
<sch:report test="exists(@tref)">Links in head should not have a tref attribute (head links should not be templated).</sch:report>
4845
<sch:let name="recognizedRels" value="'alternate' , 'stylesheet' , 'license' , 'self' , 'style' , 'self style', 'style self', 'legend', 'next', 'zoomin', 'zoomout'"></sch:let>
4946
<sch:assert test="exists(@rel) and @rel = $recognizedRels">Unrecognized link@rel value (for head link): <sch:value-of select="@rel"/>. Recognized rel values are: <sch:value-of select="$recognizedRels"/></sch:assert>
5047
</sch:rule>
51-
<sch:rule context="head/link[@type]">
48+
<sch:rule context="h:head/h:link[@type]">
5249
<sch:let name="recognizedTypes" value="'text/html','text/css','text/mapml'"></sch:let>
5350
<sch:report test="@type = $recognizedTypes">Unrecognized link@type value (for head link): <sch:value-of select="@type"/>. Recognized types are: <sch:value-of select="$recognizedTypes"/></sch:report>
5451
</sch:rule>
55-
<sch:rule context="head/link[@projection]">
52+
<sch:rule context="h:head/h:link[@projection]">
5653
<sch:report test="@rel ne 'alternate'">projection links must be rel="alternate"</sch:report>
5754
<sch:report test="exists(@type) and @type ne 'text/mapml'">If alternate projections are provided, the @type must be 'text/mapml', or be unspecified</sch:report>
5855
<sch:let name="recognizedProjections" value="'OSMTILE' , 'WGS84', 'CBMTILE', 'APSTILE'"></sch:let>
5956
<sch:report test="upper-case(@projection) = $recognizedProjections">Unrecognized link@projection value: <sch:value-of select="@projection"/></sch:report>
6057
</sch:rule>
61-
<sch:rule context="extent/link">
58+
<sch:rule context="h:extent/h:link">
6259
<sch:assert test="exists(@tref)">Links in extent should have a tref attribute (extent links must be templated).</sch:assert>
6360
<sch:report test="exists(@href)">Links in extent should not have a href attribute (extent links must be templated).</sch:report>
6461
<sch:let name="recognizedRels" value="'image' , 'tile' , 'query' , 'features'"></sch:let>
6562
<sch:assert test="exists(@rel) and @rel = $recognizedRels">Unrecognized link@rel value (for templated link): <sch:value-of select="@rel"/>. Recognized rel values are: <sch:value-of select="$recognizedRels"/></sch:assert>
6663
</sch:rule>
67-
<sch:rule context="extent/link[@type]">
64+
<sch:rule context="h:extent/h:link[@type]">
6865
<sch:let name="recognizedTypes" value="'text/mapml','image/png','image/jpeg'"></sch:let>
6966
<sch:assert test="@type = $recognizedTypes">Unrecognized link@type value (for templated link): <sch:value-of select="@type"/>. Recognized types are: <sch:value-of select="$recognizedTypes"/></sch:assert>
7067
</sch:rule>
71-
<sch:rule context="input[@name = preceding-sibling::input/@name]">
68+
<sch:rule context="h:input[@name = preceding-sibling::h:input/@name]">
7269
<sch:assert test="false()">Duplicate input/@name detected</sch:assert>
7370
</sch:rule>
74-
<sch:rule context="input[@type eq 'location' or @type eq 'zoom'][@min][@max][xs:decimal(@min) &gt; xs:decimal(@max)]">
71+
<sch:rule context="h:input[@type eq 'location' or @type eq 'zoom'][@min][@max][xs:double(@min) &gt; xs:double(@max)]">
7572
<sch:assert test="false()">@min &gt; @max detected</sch:assert>
7673
</sch:rule>
77-
<sch:rule context="link[@tref]">
74+
<sch:rule context="h:link[@tref]">
7875
<sch:assert test="local-name(parent::node()) eq 'extent'">templated links can only be in the extent element</sch:assert>
7976
</sch:rule>
80-
<sch:rule context="link[@projection]">
77+
<sch:rule context="h:link[@projection]">
8178
<!-- this rule doesn't work. don't know why. <sch:assert test="./@rel eq 'alternate'">For alternate projection links, @rel must equal 'alternate'</sch:assert>-->
8279
<sch:assert test="local-name(parent::node()) eq 'head'">Alternate projection links can only be in the head element</sch:assert>
8380
</sch:rule>
84-
<sch:rule context="link[@href]">
81+
<sch:rule context="h:link[@href]">
8582
<sch:assert test="local-name(parent::node()) ne 'extent'">regular links must not be in the extent element</sch:assert>
8683
</sch:rule>
87-
<sch:rule context="link[normalize-space(@rel) = 'self style' or normalize-space(@rel) = 'style self']">
88-
<sch:assert test="count(//link[normalize-space(@rel) = 'self style' or normalize-space(@rel) = 'style self']) eq 1">More than one self style or style self link found</sch:assert>
84+
<sch:rule context="h:link[normalize-space(@rel) = 'self style' or normalize-space(@rel) = 'style self']">
85+
<sch:assert test="count(//h:link[normalize-space(@rel) = 'self style' or normalize-space(@rel) = 'style self']) eq 1">More than one self style or style self link found</sch:assert>
8986
</sch:rule>
9087
</sch:pattern>
9188
<sch:pattern>
92-
<sch:rule context="label">
89+
<sch:rule context="h:label">
9390
<sch:assert test="exists(./@for)">A label must have a @for attribute</sch:assert>
9491
<sch:let name="forid" value="./@for"></sch:let>
9592
<sch:assert test="exists(//*[@id eq $forid])">A label must be associated to another element by label@for == element@id</sch:assert>
9693
</sch:rule>
9794
</sch:pattern>
9895
<sch:pattern>
99-
<sch:rule context="select[@id]">
96+
<sch:rule context="h:select[@id]">
10097
<sch:let name="forid" value="./@id"></sch:let>
101-
<sch:assert test="count(//label[@for eq $forid]) eq 1">There must be only one label per labelled (select) element. Duplicated label for id="<sch:value-of select="$forid"/>".</sch:assert>
98+
<sch:assert test="count(//h:label[@for eq $forid]) eq 1">There must be only one label per labelled (select) element. Duplicated label for id="<sch:value-of select="$forid"/>".</sch:assert>
10299
</sch:rule>
103100
</sch:pattern>
104101
<sch:pattern>
105-
<sch:rule context="coordinates">
102+
<sch:rule context="h:coordinates">
106103
<sch:let name="cs" value="tokenize(normalize-space(string-join((descendant::text()),' ')),' ')"></sch:let>
107104
<sch:assert test="(count($cs) mod 2) eq 0">Coordinates must be a sequence of number pairs</sch:assert>
108105
<sch:assert test="every $c in $cs satisfies ($c castable as xs:double)">Coordinates must all be numeric</sch:assert>
109106
</sch:rule>
110107
</sch:pattern>
111108
<sch:pattern>
112-
<sch:rule context="polygon/coordinates">
109+
<sch:rule context="h:polygon//h:coordinates">
113110
<sch:let name="cs" value="tokenize(normalize-space(string-join((descendant::text()),' ')),' ')"></sch:let>
114111
<sch:assert test="(count($cs) idiv 2) ge 3">A polygon's coordinates must be a sequence of three or more pairs of numbers</sch:assert>
115112
<sch:let name="first" value="subsequence($cs,1,2)"></sch:let>
@@ -118,19 +115,20 @@
118115
</sch:rule>
119116
</sch:pattern>
120117
<sch:pattern>
121-
<sch:rule context="(multilinestring|linestring)/coordinates ">
118+
<!-- -->
119+
<sch:rule context="(h:multilinestring|h:linestring)//h:coordinates ">
122120
<sch:let name="cs" value="tokenize(normalize-space(string-join((descendant::text()),' ')),' ')"></sch:let>
123121
<sch:assert test="(count($cs) idiv 2) ge 2">A linestring's coordinates must be a sequence of two or more pairs of numbers</sch:assert>
124122
</sch:rule>
125123
</sch:pattern>
126124
<sch:pattern>
127-
<sch:rule context="multipoint/coordinates ">
125+
<sch:rule context="h:multipoint//h:coordinates ">
128126
<sch:let name="cs" value="tokenize(normalize-space(string-join((descendant::text()),' ')),' ')"></sch:let>
129127
<sch:assert test="(count($cs) idiv 2) ge 2">A multipoint's coordinates should be a sequence of two or more pairs of numbers. Should you use a point, instead?</sch:assert>
130128
</sch:rule>
131129
</sch:pattern>
132130
<sch:pattern>
133-
<sch:rule context="coordinates//span">
131+
<sch:rule context="h:coordinates//h:span">
134132
<sch:let name="cs" value="tokenize(normalize-space(string-join((descendant::text()),' ')),' ')"></sch:let>
135133
<sch:assert test="(count($cs) mod 2) eq 0">A span in coordinates should wrap coordinate pairs.</sch:assert>
136134
<!-- TODO: a test that the first number in a span is an odd number of positions into the overall set of tokens i.e. 1,3,5, etc -->

0 commit comments

Comments
 (0)