Skip to content

Commit d7205a1

Browse files
authored
Merge pull request #240 from prushforth/update-schema
Update schema
2 parents da18d36 + 63c54c7 commit d7205a1

7 files changed

Lines changed: 376 additions & 92 deletions

File tree

schema/README.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,35 @@ many of the elements are extended from the HTML namespace and are intended to ha
1010
identical processing semantics to their counterpart in HTML apart from extensions specified in MapML.
1111

1212
In practice, no such MapML/HTML parser exists at the time of writing, and it should be good enough to encode
13-
a MapML document in HTML5 XML syntax so that Web browsers' XML parsers can be used. When such a parser is used,
14-
it should be possible to use the schema / schematron documents in this directory to validate certain
15-
rules of MapML documents. The schemas / schematron files in this directory are intended to
13+
a MapML document in HTML5 XML syntax in the XHTML namespace, so that Web browsers'
14+
XML parsers can be used. When such a parser is used, it should be possible to use
15+
the schema / schematron documents in this directory to validate certain
16+
rules of MapML and XHTML documents. The schemas / schematron files in this directory are intended to
1617
evolve as the concept of MapML evolves.
1718

1819
## Instructions
1920

20-
mapml.rnc (a [RelaxNG](http://www.relaxng.org/compact-tutorial-20030326.html) compact syntax schema) and mapml.sch (post-schema validation MapML
21-
schematron rules) are intended to be applied in that order.
21+
mapml.rnc (a [RelaxNG](http://www.relaxng.org/compact-tutorial-20030326.html) compact syntax schema)
22+
and mapml.sch (post-schema validation MapML schematron rules) are intended to be
23+
applied in that order, to validate a "stand-alone" MapML document. Such a document
24+
would be loaded into an HTML document by the <layer-> custom element, via a URL
25+
reference in the src attribute: `<layer- src="URL to MapML document goes here"></layer->`.
26+
27+
Another scenario that is conceptually supported is to have an (X)HTML document that
28+
contains a <mapml-viewer> element that contains one or more <layer-> elements that
29+
in turn contain 'inline' MapML content, i.e. MapML vocabulary elements contained
30+
within the <layer-></layer-> begin and end tags.
31+
32+
I couldn't get a version of an rnc schema for xhtml to work, so I have to be satisfied
33+
with validating a document that contains only a `<mapml-viewer>` element, with the
34+
correct namespace xmlns value for XHTML. See mapml-viewer.xhtml as an example.
35+
36+
To validate this latter type of document, I 'forked' the mapml.rnc document into
37+
mapml-viewer.rnc. You can validate mapml-viewer.xhtml and similar documents by
38+
using the mapml-viewer.rnc schema validation phase, followed by the mapml-viewer.sch
39+
schematron validation. These scenarios may not be perfectly adapted; please get
40+
in touch if you have a document that doesn't validate, but you think it should,
41+
or vice versa.
2242

2343
I use the Oxygen XML editor to create a global validation scenario for MapML documents,
2444
but you can use any engines which support those technologies, I believe.

schema/mapml-document.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!-- validate with mapml.rnc, then mapml.sch. Use via <layer- src="..."> attribute -->
2+
<mapml- xmlns="http://www.w3.org/1999/xhtml">
3+
<map-head>
4+
<map-title>Canada Base Map - Geometry</map-title>
5+
<map-meta http-equiv="Content-Type" content="application/xml;charset=UTF-8"/>
6+
<map-meta charset="utf-8"/>
7+
<map-meta name="projection" content="CBMTILE" />
8+
<map-base href="/mapml/en/cbmtile/cbmtgeom/"/>
9+
<map-link rel="license" href="https://open.canada.ca/en/open-government-licence-canada"
10+
title="Open Government Licence - Canada"/>
11+
<map-link rel="legend"
12+
href="https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_CBCT_GEOM_3978/MapServer/legend"
13+
/>
14+
</map-head>
15+
<map-body>
16+
<map-extent units="CBMTILE">
17+
<map-input name="z" type="zoom" value="18" min="0" max="18"/>
18+
<map-input name="y" type="location" units="tilematrix" axis="row" min="51599"
19+
max="61455"/>
20+
<map-input name="x" type="location" units="tilematrix" axis="column" min="46501"
21+
max="56244"/>
22+
<map-link rel="tile"
23+
tref="https://geoappext.nrcan.gc.ca/arcgis/rest/services/BaseMaps/CBMT_CBCT_GEOM_3978/MapServer/tile/{z}/{y}/{x}?m4h=t"
24+
/>
25+
</map-extent>
26+
</map-body>
27+
</mapml->

schema/mapml-viewer.rnc

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes"
2+
default namespace = "http://www.w3.org/1999/xhtml"
3+
start = mapml-viewer
4+
mapml-viewer = element mapml-viewer { layer-*,
5+
attribute lat {text},
6+
attribute lon {text},
7+
attribute zoom {text},
8+
attribute projection { "OSMTILE" | "CBMTILE" | "APSTILE" | "WGS84" },
9+
attribute controls {text}?,
10+
attribute controlslist { text }?,
11+
attribute height {text}?,
12+
attribute width {text}?,
13+
attribute static {text}?,
14+
map-caption?,
15+
layer-*
16+
}
17+
map-caption = element map-caption { text }
18+
layer- = element layer- {
19+
attribute src { xsd:anyURI }?,
20+
attribute label {text}?,
21+
attribute checked {text}?,
22+
attribute hidden {text}?,
23+
attribute opacity {text}?,
24+
(headContent?, bodyContent+)
25+
}*
26+
map-link = element map-link {
27+
attribute href { xsd:anyURI }?,
28+
# can have a tref (when in extent) or an href (but not both)
29+
attribute tref { text }?,
30+
# @rel=alternate + @projection=tcrs-name is proposed as a way of negotiating the tcrs of the service: https://github.com/Maps4HTML/MapML/issues/11
31+
attribute rel { text },
32+
attribute projection { "OSMTILE" | "CBMTILE" | "APSTILE" | "WGS84" }?,
33+
attribute title { text }?,
34+
attribute type { text }?,
35+
attribute hreflang { text }?
36+
}
37+
map-links = map-link*
38+
headContent =
39+
element map-base {
40+
attribute href {text}
41+
}? &
42+
element map-meta {
43+
attribute name {text}?,
44+
attribute charset {text}?,
45+
attribute content {text}?,
46+
attribute http-equiv {text}?
47+
}* &
48+
element map-style { text }? &
49+
element map-title { text }? &
50+
map-links
51+
bodyContent = map-extent? & map-links & (map-feature | map-tile | map-image)*
52+
map-extent = element map-extent {
53+
attribute units { "OSMTILE" | "CBMTILE" | "APSTILE" | "WGS84" }?,
54+
(map-inputs* & map-links* & select* & label*)?
55+
}
56+
map-inputs = (element map-input {
57+
attribute name { text },
58+
# xmin, ymin, xmax, ymax and projection are deprecated. If you need to transmit a projection, use a hidden input/variable
59+
# for xmin etc, use a input@type=location with appropriate position, units, axis values.
60+
attribute type { "zoom" | "hidden" | "location" | "datetime" | "width" | "height" },
61+
attribute value { text }?,
62+
attribute rel { "image" | "tile" | "pixel" }?,
63+
attribute shard { text }?,
64+
attribute list { text }?,
65+
# position tokens are based on /composed from the set of keywords used for CSS object-position, but they are obviously unique tokesn and not combinable otherwise
66+
# https://developer.mozilla.org/en-US/docs/Web/CSS/object-position
67+
attribute position { "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center-left" | "center-right" | "top-center" | "bottom-center" | "center" }?,
68+
attribute axis { "latitude" | "longitude" | "easting" | "northing" | "x" | "y" | "row" | "column" | "i" | "j" }?,
69+
attribute units {"gcrs" | "pcrs" | "tcrs" | "map" | "tilematrix" | "tile" }?,
70+
attribute required { xsd:boolean }?,
71+
attribute min { xsd:double }?,
72+
attribute max { xsd:double }?,
73+
attribute step { text }?
74+
})
75+
label = element map-label {
76+
attribute for { text },
77+
text
78+
}
79+
select = element map-select {
80+
attribute id { text },
81+
attribute name { text },
82+
option+
83+
}
84+
option = element map-option {
85+
attribute value { text }?,
86+
attribute label { text }?,
87+
text
88+
}
89+
map-feature = element map-feature {
90+
attribute id { text }?,
91+
attribute class { text }?,
92+
attribute zoom { text }?,
93+
attribute min { text }?,
94+
attribute max { text }?,
95+
(map-geometry? & map-properties? & map-featurecaption?)
96+
}
97+
map-tile = element map-tile {
98+
attribute col { xsd:integer },
99+
attribute row { xsd:integer },
100+
ImageResourceMetadataAttributes
101+
}
102+
bbox = element map-bbox { twoPositions }
103+
map-image = element map-image { ImageModel }
104+
105+
map-geometry = element map-geometry {
106+
attribute cs { "gcrs" | "pcrs" | "tcrs" | "map" | "tilematrix" | "tile" }?,
107+
(GeometryContent | map-a)
108+
}
109+
map-properties = element map-properties { PropertyContent }
110+
map-featurecaption = element map-featurecaption { text? }
111+
112+
ImageResourceMetadataAttributes =
113+
attribute src { text },
114+
imageLocation?,
115+
imageSize?,
116+
attribute angle { xsd:double }?,
117+
attribute type { text }?
118+
ImageModel = ImageResourceMetadataAttributes
119+
# allow any property/value via simple elements with allowed text content
120+
# see https://www.oreilly.com/library/view/xml-pocket-reference/9780596100506/re92.html
121+
PropertyContent = any_element
122+
any_element = element * { (attribute * { text } | text | any_element)* }
123+
any_attribute = attribute * { text }
124+
imageLocation = attribute x { xsd:double }, attribute y { xsd:double }
125+
imageSize = attribute width { xsd:integer },attribute height { xsd:integer }
126+
127+
GeometryContent = map-point | map-linestring | map-polygon | map-multipoint | map-multilinestring | map-multipolygon | map-geometrycollection
128+
map-a = element map-a {
129+
attribute href { text },
130+
attribute target { "_self" | "_top" | "_blank" | "_parent" }?,
131+
attribute type { "text/mapml" | "text/html" }?,
132+
(GeometryContent | text | span_element | coordinates_mixed)}
133+
map-point = element map-point { map-a | coordinates_mixed }
134+
map-linestring = element map-linestring { map-a | coordinates_mixed }
135+
map-polygon = element map-polygon { map-a* & coordinates_mixed+ }
136+
map-multipoint = element map-multipoint { map-a | coordinates_mixed }
137+
map-multilinestring = element map-multilinestring { map-a* & coordinates_mixed+ }
138+
map-multipolygon = element map-multipolygon { map-a* & map-polygon+ }
139+
map-geometrycollection = element map-geometrycollection {
140+
(map-point* & map-linestring* & map-polygon* & map-multipoint* & map-multilinestring* & map-multipolygon*)
141+
}
142+
span_element = element map-span {
143+
mixed {
144+
attribute * { text }*&
145+
span_element* &
146+
map-a*
147+
}
148+
}
149+
coordinates_mixed = element map-coordinates { mixed { span_element* & map-a* } }
150+
# for bbox content, omits coordinates element
151+
twoPositions = list { (xsd:double, xsd:double, xsd:double, xsd:double) }
152+

schema/mapml-viewer.sch

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?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" 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:layer-">
7+
<sch:assert test="local-name(parent::*) eq 'mapml-viewer'">The layer- element must be a child of the mapml-viewer element</sch:assert>
8+
<sch:assert test="((exists(@src) and not(exists(./*))) or (not(exists(@src)) and exists(./*)))">The &lt;layer-&gt; element must have either a src attribute or inline content</sch:assert>
9+
</sch:rule>
10+
<sch:rule context="h:layer-[child::h:map-title]/@label">
11+
<sch:assert test="false()">In the case that a label attribute exists and a map-title element is present, the map-title will be preferred.</sch:assert>
12+
</sch:rule>
13+
<sch:rule context="h:layer">
14+
<sch:assert test="false()">The layer- element MUST have a trailing hyphen: layer-</sch:assert>
15+
</sch:rule>
16+
</sch:pattern>
17+
<sch:pattern>
18+
<sch:rule context="h:mapml-viewer">
19+
<!-- <sch:assert test="ancestor::h:body">The mapml-viewer element must be a descendant of the html &lt;body&gt; element</sch:assert>
20+
<sch:assert test="ancestor::h:html">The mapml-viewer element must be a descendant of the &lt;html&gt; element</sch:assert>-->
21+
<sch:assert test="every $exists in (exists(@projection),exists(@lat),exists(@lon),exists(@zoom)) satisfies $exists">The mapml-viewer element must have the projection, lat, lon and zoom attributes</sch:assert>
22+
<sch:assert test="some $prj in ('OSMTILE','CBMTILE','WGS84','APSTILE') satisfies $prj eq @projection">The projection attribute must have a value that is one of: 'OSMTILE','CBMTILE','WGS84' or 'APSTILE'</sch:assert>
23+
<sch:assert test="matches(attribute(lat), '^-?\d+\.?\d*$')">The value of lat attribute must be a number</sch:assert>
24+
<sch:assert test="matches(attribute(lon), '^-?\d+\.?\d*$')">The value of lon attribute must be a number</sch:assert>
25+
<sch:assert test="matches(attribute(zoom), '^([0-9]|1[0-9]|2[0-6])$')">The value of zoom attribute must be an integer between 0 and 26</sch:assert>
26+
<sch:assert test="attribute(lon) castable as xs:decimal and xs:decimal(attribute(lon)) ge -180.0 and xs:decimal(attribute(lon)) le 180.0">lon attribute must be greater than or equal to -180 and less than or equal to 180</sch:assert>
27+
<sch:assert test="attribute(lat) castable as xs:decimal and xs:decimal(attribute(lat)) ge -90.0 and xs:decimal(attribute(lat)) le 90.0">lat attribute must be greater than or equal to -90 and less than or equal to 90</sch:assert>
28+
<sch:assert test="every $control in tokenize(@controlslist,' ') satisfies not(empty(('nolayer','nozoom','noreload','nofullscreen','noscale','geolocation')[. eq $control]))">controlslist value must be one or more of ('nolayer','nozoom','noreload','nofullscreen','noscale','geolocation')</sch:assert>
29+
</sch:rule>
30+
</sch:pattern>
31+
</sch:schema>

schema/mapml-viewer.xhtml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!-- validate with mapml-viewer.rnc, then mapml-viewer.sch. <mapml-viewer> is a
2+
custom element that goes in the <body> element of an HTML document -->
3+
<mapml-viewer lat="45" lon="180" projection="CBMTILE" zoom="11" controls="controls" height="240" controlslist="nofullscreen geolocation noscale" xmlns="http://www.w3.org/1999/xhtml">
4+
<map-caption>A pleasing map of Canada</map-caption>
5+
<layer- src=""></layer->
6+
<layer- label="CBMT" src="https://geogratis.gc.ca/mapml/en/cbmtile/cbmt/" checked="foo"></layer->
7+
<layer- label="Hat Guy" checked="foo">
8+
<map-meta name="foo" content="CBMTILE"></map-meta>
9+
<map-feature id="twohats" zoom="15" class="twohats">
10+
<map-properties>
11+
<table>
12+
<tr>
13+
<th>code</th>
14+
<td>1200020</td>
15+
</tr>
16+
<tr>
17+
<th>accuracy</th>
18+
<td>26</td>
19+
</tr>
20+
<tr>
21+
<th>valdate</th>
22+
<td>1995</td>
23+
</tr>
24+
<tr>
25+
<th>image</th>
26+
<td><a
27+
href="https://www.veterans.gc.ca/eng/remembrance/memorials/national-inventory-canadian-memorials/details/9304">
28+
<img
29+
src="https://www.veterans.gc.ca/images/remembrance/memorials/national-inventory-canadian-memorials/mem/35059-173a.jpg"
30+
width="60" height="60" />
31+
</a>
32+
</td>
33+
</tr>
34+
<tr>
35+
<th>theme</th>
36+
<td>FO</td>
37+
</tr>
38+
<tr>
39+
<th>type</th>
40+
<td>2</td>
41+
</tr>
42+
<tr>
43+
<th>elevation</th>
44+
<td>61</td>
45+
</tr>
46+
<tr>
47+
<th>altiaccu</th>
48+
<td>5</td>
49+
</tr>
50+
</table>
51+
</map-properties>
52+
<map-geometry cs="gcrs">
53+
<map-point>
54+
<map-coordinates>-75.705278 45.397778</map-coordinates>
55+
</map-point>
56+
</map-geometry>
57+
</map-feature>
58+
</layer->
59+
</mapml-viewer>

0 commit comments

Comments
 (0)