# Redefine atom:feed to include new owc and dc elements atomFeedConstruct &= owcDisplay? & element dc:publisher { text } & element dc:date { atomDateConstruct }? & georssWhere ?And imposes a new rule for the atom:feed by stating that it needs to have a atom:category with @scheme='http://www.opengis.net/owc/specReference'
s:rule [ context = "atom:feed" s:assert [ test = "atom:category[@scheme='http://www.opengis.net/owc/specReference']" "An atom:feed must have an atom:category with the OWC " ~ "specification reference identified with the " ~ " @scheme='http://www.opengis.net/owc/specReference' "]] ]
# Redefine atom:entry to include new owc and dc elements atomEntryConstruct &= owcOffering? & element dc:publisher { text }? & element dc:date { atomDateConstruct }? & georssWhere ? & element owc:minScaleDenominator { xsd:float }? & element owc:maxScaleDenominator { xsd:float }?And imposes a new rule on this element that it must have a human readable content element
s:rule [ context = "atom:entry" s:assert [ test = "atom:content" "An atom:entry must have one atom:content MUST have content " ~ "element in a format understandable by generic Atom readers" ~ " ( @type equal to 'html' is recommended)"]]
# owcOffering owcOffering = element owc:offering { owcCommonAttributes, attribute code { text }, ( owcOperation* & owcContent* & owcStyleSet* & extensionElement*) }
# owcOperation owcOperation = element owc:operation { owcCommonAttributes, attribute code { text }, attribute href { owcHTTPURL }, attribute type { text }?, ( ( attribute method {"GET"} & element owc:result{(extensionElement*)}? & extensionElement* ) | ( attribute method {"POST"} & element owc:result{(extensionElement*)}? & element owc:payload {( extensionElement* )}? & extensionElement* ) ) }
owcContent = element owc:content { owcCommonAttributes & ( ( attribute type { text }, attribute href { owcHTTPURL }) | ( attribute type { text }, ( text | anyElement)* ) ) }
owcStyleSet = element owc:styleSet { owcCommonAttributes, attribute default { "0" | "1" } ?, (element owc:name { text } & element owc:title { text } & element owc:abstract { text }? & element owc:legendURL { attribute type { text }, attribute href { owcHTTPURL } }? & element owc:content { owcContent }? & extensionElement*) }
# Replacing definitions on RFC4287 include "rfc4287.rnc"{ # Redefine the Simple Extension to exclude owc:* elements simpleExtensionElement = element * - (atom:* | owc:* | dc:publisher | dc:date | georss:where) { text } # Redefine the Structured Extension to exclude owc:* elements structuredExtensionElement = element * - (atom:* | owc:* | dc:publisher | dc:date | georss:where) { (attribute * { text }+,(text|anyElement)*) | (attribute * { text }*, (text?, anyElement+, (text|anyElement)*))} }
namespace georss="http://www.georss.org/georss" namespace gml="http://www.opengis.net/gml" georssWhere = element georss:where { gmlElement } gmlElement = (gmlPointElement | gmlLineStringElement | gmlPolygonElement | gmlEnvelopeElement ) gmlPointElement = element gml:Point { element gml:pos { list { xsd:decimal, xsd:decimal }} } gmlLineStringElement = element gml:LineString { element gml:posList { list { (xsd:decimal, xsd:decimal)+ }} } gmlPolygonElement = element gml:Polygon { element gml:exterior { element gml:LinearRing { element gml:posList { list { (xsd:decimal, xsd:decimal)+ }}}} } gmlEnvelopeElement = element gml:Envelope { element gml:lowerCorner { list { xsd:decimal, xsd:decimal } } & element gml:upperCorner { list { xsd:decimal, xsd:decimal } } }
java -jar ../lib/trang/trang.jar -I rnc -O rng ../relaxng/owc10.rnc ../relaxng/owc10.rng
java -jar ../lib/relames/relames.jar ../relaxng/owc10.rng ../../web/examples/meris_borders_users.atom
java -jar ../lib/jing/bin/jing.jar -c ../relaxng/owc10.rnc ../../web/examples/meris_borders_users.atom
xsltproc --stringparam entry "topp:member_map" --stringparam now "`date +%Y-%m-%dT%H:%M:%S`" --stringparam mode "fragment" ows2owc.xsl 'http://meet.opengeospatial.org:8080/geoserver/ows?service=WFS&request=GetCapabilities'creates the following file:
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:owc="http://www.opengis.net/owc/1.0/" xmlns:ows="http://www.opengis.net/ows"> <id>http://meet.opengeospatial.org:8080/geoserver/wfstopp:member_map/</id> <title>OGC members</title> <author><name>Raj Singh</name></author> <dc:publisher>Open Geospatial Consortium</dc:publisher> <updated>2012-12-20T17:01:57Z</updated> <dc:rights>Fee:NONE / Contraints:NONE</dc:rights> <georss:where> <gml:Polygon><gml:exterior><gml:LinearRing> <gml:posList>-41.302 -157.862 -41.302 174.805 60.671 174.805 60.671 -157.862 -41.302 -157.862</gml:posList> </gml:LinearRing></gml:exterior></gml:Polygon> </georss:where> <link rel="enclosure" type="text/xml; subtype=gml/3.1.1" title="WFS output for OGC members" href="http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&BBOX=-41.302,-157.862,60.671,174.805&OUTPUTFORMAT=text/xml; subtype=gml/3.1.1&TYPENAME=topp:member_map&MAXFEATURES=10"/> <link rel="describedby" type="text/xml" title="Description of Features" href="http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=describeFeatureType&TYPENAME=topp:member_map"/> <link rel="via" type="text/xml" title="Original GetCapabilities document" href="http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetCapabilities"/> <content type="html"> <br/> This resource is available from a OGC WFS Service (version 1.1.0) and it contains the following access points: <ul><li> <a href='http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&BBOX=-41.302,-157.862,60.671,174.805&OUTPUTFORMAT=text/xml; subtype=gml/3.1.1&TYPENAME=topp:member_map&MAXFEATURES=10'> GetFeature </a> request in text/xml; subtype=gml/3.1.1 (atom:link[@rel="enclosure"]) </li> <li> <a href='http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetCapabilities'> GetCapabilities </a> request (atom:link[@rel="via"]) </li> </li> <li> <a href='http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=describeFeatureType&TYPENAME=topp:member_map'> Describe Feature </a> request for topp:member_map (atom:link[@rel="describedby"]) </li></ul> <p style='font-size:small'>OGC Context CITE Testing XSLT (Extensible Stylesheet Language Transformations) by Terradue Srl.</p> </content> <owc:offering code="http://www.opengis.net/spec/owc/1.0/req/atom/wfs"> <owc:operation method="GET" code="GetCapabilities" href="http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetCapabilities"/> <owc:operation method="GET" code="GetFeature" href="http://meet.opengeospatial.org:8080/geoserver/wfs?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&BBOX=-41.302,-157.862,60.671,174.805&OUTPUTFORMAT=text/xml; subtype=gml/3.1.1&TYPENAME=topp:member_map&MAXFEATURES=10"/> </owc:offering> </entry>This transformation file work by going for each layer or feature and creates a new Atom entry with a owc:offering element
<xsl:template match="wms:Layer | Layer | wfs:FeatureType"> <entry> ... <owc:offering> <xsl:attribute name="code"><xsl:value-of select="$offering_code"/></xsl:attribute> <owc:operation method="GET" code="GetCapabilities"> <xsl:attribute name="href"> <xsl:value-of select="$get_capabilities_request"/> </xsl:attribute> </owc:operation> <owc:operation method="GET"> <xsl:attribute name="code"><xsl:value-of select="$default_operation"/></xsl:attribute> <xsl:attribute name="href"><xsl:value-of select="$get_request"/></xsl:attribute> </owc:operation> <xsl:for-each select="wms:Style | Style"> <owc:styleSet> <owc:name><xsl:value-of select="wms:Name | Name"/></owc:name> <owc:title><xsl:value-of select="wms:Title | Title"/></owc:title> <owc:abstract><xsl:value-of select="wms:Abstract | Abstract"/></owc:abstract> <owc:legendURL> <xsl:attribute name="href"> <xsl:value-of select="wms:LegendURL/wms:OnlineResource/@xlink:href | LegendURL/OnlineResource/@xlink:href"/> </xsl:attribute> <xsl:attribute name="type"> <xsl:value-of select="wms:LegendURL/wms:Format | LegendURL/Format"/> </xsl:attribute> </owc:legendURL> </owc:styleSet> </xsl:for-each> </owc:offering> ... </entry>To define the service GetCapabilities? request first it is necessary to obtain the service name, version and online resource for the serivce
<xsl:variable name="service_name"><xsl:choose> <xsl:when test="/wfs:WFS_Capabilities">WFS</xsl:when> <xsl:when test="/wms:WMS_Capabilities | /WMT_MS_Capabilities">WMS</xsl:when> <xsl:otherwise>UNKNOWN</xsl:otherwise></xsl:choose> </xsl:variable> <xsl:variable name="version" select="/*/@version"/> <xsl:variable name="capabilities_online_resource" select="/wms:WMS_Capabilities/wms:Capability/wms:Request/wms:GetCapabilities/wms:DCPType/wms:HTTP/wms:Get/wms:OnlineResource/@xlink:href | /WMT_MS_Capabilities/Capability/Request/GetCapabilities/DCPType/HTTP/Get/OnlineResource/@xlink:href | /*/ows:OperationsMetadata/ows:Operation[@name='GetCapabilities']/ows:DCP/ows:HTTP/ows:Get/@xlink:href"/> <xsl:variable name="get_capabilities_request"> <xsl:value-of select="$capabilities_online_resource"/> <xsl:if test="substring-before($capabilities_online_resource,'?')=''">?</xsl:if> <xsl:value-of select="concat('SERVICE=',$service_name,'&VERSION=',$version,'&REQUEST=GetCapabilities')"/> </xsl:variable>To define the entry's bounding box, the XSLT file will look for the layer's bounding box element value or value of its ancestors bounding box element. This way it solves the issue of nested layers in WMS or when spatial is defined only at the top most layer.
<xsl:variable name="maxX"> <xsl:choose> <xsl:when test="$bbox!=''"><xsl:value-of select="$coords/*[3]"/></xsl:when> <xsl:when test="ows:WGS84BoundingBox/ows:UpperCorner"> <xsl:value-of select="substring-before(ows:WGS84BoundingBox/ows:UpperCorner,' ')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="ancestor-or-self::wms:Layer/wms:EX_GeographicBoundingBox/wms:eastBoundLongitude | ancestor-or-self::Layer/LatLonBoundingBox/@maxx"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="maxY"> <xsl:choose> <xsl:when test="$bbox!=''"><xsl:value-of select="$coords/*[4]"/></xsl:when> <xsl:when test="ows:WGS84BoundingBox/ows:UpperCorner"> <xsl:value-of select="substring-after(ows:WGS84BoundingBox/ows:UpperCorner,' ')"/> </xsl:when> <xsl:otherwise><xsl:value-of select="ancestor-or-self::wms:Layer/wms:EX_GeographicBoundingBox/wms:northBoundLatitude | ancestor-or-self::Layer/LatLonBoundingBox/@maxy"/></xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="minX"> <xsl:choose> <xsl:when test="$bbox!=''"><xsl:value-of select="$coords/*[1]"/></xsl:when> <xsl:when test="ows:WGS84BoundingBox/ows:LowerCorner"> <xsl:value-of select="substring-before(ows:WGS84BoundingBox/ows:LowerCorner,' ')"/> </xsl:when> <xsl:otherwise><xsl:value-of select="ancestor-or-self::wms:Layer/wms:EX_GeographicBoundingBox/wms:westBoundLongitude | ancestor-or-self::Layer/LatLonBoundingBox/@minx"/></xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="minY"> <xsl:choose> <xsl:when test="$bbox!=''"><xsl:value-of select="$coords/*[2]"/></xsl:when> <xsl:when test="ows:WGS84BoundingBox/ows:LowerCorner"> <xsl:value-of select="substring-after(ows:WGS84BoundingBox/ows:LowerCorner,' ')"/> </xsl:when> <xsl:otherwise><xsl:value-of select="ancestor-or-self::wms:Layer/wms:EX_GeographicBoundingBox/wms:southBoundLatitude | ancestor-or-self::Layer/LatLonBoundingBox/@miny"/></xsl:otherwise> </xsl:choose> </xsl:variable>It uses then these values to define the entry's GEORSS element
<georss:where> <gml:Polygon> <gml:exterior> <gml:LinearRing> <gml:posList> <xsl:value-of select="concat($minY,' ',$minX,' ',$minY,' ',$maxX,' ',$maxY,' ',$maxX,' ',$maxY,' ',$minX,' ',$minY,' ',$minX)"/> </gml:posList> </gml:LinearRing> </gml:exterior> </gml:Polygon> </georss:where>These values are also used to define the bbox request by checking the CRS code to use
<!-- preference for Plate Carre on element --> <!-- if no crs available then check parent --> <xsl:variable name="crs"> <xsl:choose> <xsl:when test="count(wms:CRS[.='EPSG:4326'] | SRS[.='EPSG:4326'])!=0">EPSG:4326</xsl:when> <xsl:when test="count(wms:CRS[.='CRS:84'] | SRS[.='CRS:84'])!=0">CRS:84</xsl:when> <xsl:when test="count(wms:CRS[1] | SRS[1])!=0"><xsl:value-of select="wms:CRS[1] | SRS[1]"/></xsl:when> <xsl:when test="count(ancestor::wms:Layer/wms:CRS[.='EPSG:4326'] | ancestor::Layer/SRS[.='EPSG:4326'])!=0">EPSG:4326</xsl:when> <xsl:when test="count(ancestor::wms:Layer/wms:CRS[.='CRS:84'] | ancestor::Layer/SRS[.='CRS:84'])!=0">CRS:84</xsl:when> <xsl:otherwise><xsl:value-of select="ancestor::wms:Layer/wms:CRS[1] | ancestor::Layer/SRS[1]"/></xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="bbox"> <xsl:choose> <xsl:when test="($service_name='WMS' and $version='1.3.0' and $crs='EPSG:4326') or /wfs:WFS_Capabilities"> <xsl:value-of select="concat($minY,',',$minX,',',$maxY,',',$maxX)"/></xsl:when> <xsl:otherwise> <xsl:value-of select="concat($minX,',',$minY,',',$maxX,',',$maxY)"/> </xsl:otherwise> </xsl:choose> </xsl:variable>To create the request it is necessary to join all those parameters
<xsl:variable name="get_request"> <xsl:value-of select="$operation_online_resource"/><xsl:if test="substring-before($operation_online_resource,'?')=''">?</xsl:if><xsl:value-of select="concat('SERVICE=',$service_name, '&VERSION=',$version,'&REQUEST=',$default_operation,'&BBOX=',$bbox)"/><xsl:choose> <xsl:when test="$service_name='WFS'"><xsl:value-of select="concat('&OUTPUTFORMAT=',$data_format,'&TYPENAME=',$name,'&MAXFEATURES=10')"/> </xsl:when> <xsl:when test="$service_name='WMS'"><xsl:value-of select="concat( $crsName, '=',$crs,'&WIDTH=',floor($map_height * $georatio),'&HEIGHT=',$map_height,'&LAYERS=',$name,'&FORMAT=',$data_format,'&BGCOLOR=0xffffff&TRANSPARENT=TRUE&EXCEPTIONS=',$exception_format)"/> </xsl:when> <xsl:otherwise/> </xsl:choose> </xsl:variable>
Access the full XSLT transformation in the trax github site.