如何从Geosparql的wktLiteral检索纬度和经度?

4

我正在处理包含地理参考信息的RDF数据,例如具有指定位置的POI:

@prefix ogc:   <http://www.opengis.net/ont/geosparql#> .

:poi  ogc:hasGeometry  :geo
:geo  ogc:asWKT        "POINT(48.5 11.7)"^^ogc:wktLiteral .

有一个POI位于(48.5, 11.7)的位置。 我可以使用GeoSPARQL-查询来处理这些位置,但现在我想分别提取纬度和经度,以便将其输入到另一个不支持WKT的应用程序中。

SELECT ?lat ?lon
WHERE {
    # how do I get lat and lon from "POINT(48.5 11.7)"^^ogc:wktLiteral?
}

OGC的GeoSPARQL规范中,我没有找到任何有用的内容,因此我想知道在SPARQL查询中手动提取这种数据的最佳方法。

2个回答

5

使用正则表达式来处理这种类型的内容总是有点棘手,尤其是当我们没有一个精确的语法可供使用时,但我认为以下方法有效(注意:这仅适用于正值;对于负值,请参阅其他答案以获得能够处理负值的模式):

prefix ogc: <urn:ex:>

select ?lat ?long where {
  values ?point { "POINT(48.5 11.7)"^^ogc:wktLiteral }
  bind( replace( str(?point), "^[^0-9\\.]*([0-9\\.]+) .*$", "$1" ) as ?long )
  bind( replace( str(?point), "^.* ([0-9\\.]+)[^0-9\\.]*$", "$1" ) as ?lat )
}

-------------------
| lat    | long   |
===================
| "11.7" | "48.5" |
-------------------

关键在于正则表达式。
"^[^0-9\\.]*([0-9\\.]+) .*$" === <non-number>(number) <anything>
"^.* ([0-9\\.]+)[^0-9\\.]*$" === <anything> (number)<non-number>

当然,这只是一个对于number的近似值,因为它会匹配带有多个点的内容,但如果数据是好的,你不应该有问题。如果你需要将这些值转换为数值类型,你也可以进行这种类型的转换:
prefix ogc: <urn:ex:>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>

select ?lat ?long where {
  values ?point { "POINT(48.5 11.7)"^^ogc:wktLiteral }
  bind( xsd:decimal( replace( str(?point), "^[^0-9\\.]*([0-9\\.]+) .*$", "$1" )) as ?long )
  bind( xsd:decimal( replace( str(?point), "^.* ([0-9\\.]+)[^0-9\\.]*$", "$1" )) as ?lat )
}

---------------
| lat  | long |
===============
| 11.7 | 48.5 |  # note: no quotation marks; these are numbers
---------------

请注意,还有其他类型的WKT点,而这段代码无法正确处理它们。例如,维基百科的Well-known text文章中的一些示例:
POINT ZM (1 1 5 60)
POINT M (1 1 80)
POINT EMPTY

1
点的WKT定义是POINT(X Y),所以应该是POINT(LNG LAT)。这里你的纬度和经度颠倒了。 - lreeder
抱歉,我的习惯。我在评论中删除了X、Y之间的逗号。 - lreeder
@lreeder 好的,我会解决经纬度问题。找出了个漏洞。 - Joshua Taylor
@Klamann 是的,我实际上简化了很多,使用了组和替换文本,所以现在只需要一个 replace 调用。在我看来,现在好多了。 - Joshua Taylor
1
这个答案没有考虑到负值,而另一个答案则有。 - logi-kal
显示剩余3条评论

2

Joshua的回答没有考虑到纬度或经度为负值的情况。对此进行更正:

prefix ogc: <urn:ex:>
select ?lat ?long where {
   values ?point { "POINT(48.5 -11.7)"^^ogc:wktLiteral }
   bind( replace( str(?point), "^[^0-9\\.-]*([-]?[0-9\\.]+) .*$", "$1" ) as ?long )
   bind( replace( str(?point), "^.* ([-]?[0-9\\.]+)[^0-9\\.]*$", "$1" ) as ?lat )
}

以及结果

--------------------
| lat     | long   |
===================
| "-11.7" | "48.5" |
--------------------

我已经使用Rubular测试了正则表达式,并在Parliament SPARQL端点上测试了GeoSPARQL查询,看起来没问题。


这应该是被接受的答案。 - logi-kal
1
@logi-kal 我也给你点赞。我在原回答中确实没有考虑到负值的情况。 - Joshua Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接