将 JSON 转换为 QGIS GeoJSON:同时具有多种功能和不同类型

Posted

技术标签:

【中文标题】将 JSON 转换为 QGIS GeoJSON:同时具有多种功能和不同类型【英文标题】:Converting JSON to QGIS GeoJSON: while having multiple features and different types 【发布时间】:2021-05-16 03:06:57 【问题描述】:

目前我有一个从特定 API 请求 JSONS 的程序。 API 的创建者声称此数据在 GeoJSON 中,但 QGIS 无法读取。

所以我想扩展我的 Python 脚本以将 JSON 以可读格式转换为 GEOJSON 以进入 QGIS 并在那里进一步处理。

但是,我有一些问题, 一个我不知道从哪里开始以及 JSON 文件是如何构建的......它有点混乱。 JSONS 实际上是基于两个 API Get Request 制作的。第一个 Api Get Request 请求点数,第二个请求点数的详细信息。有关更多上下文,请参见此处的此问题: API Request within another API request (Same API) in Python

请注意,由于字数限制,我无法在此处发布代码:

这些细节当然应该是这些点周围区域的“轮廓”。 问题是.. JSON 中提到了点本身,因此很难指定每个点的坐标。更不用说我们感兴趣的所有其他属性,都在 GeoJSON 的“点”部分。

看看 JSON 本身就明白我的意思了:


    "comment": null,
    "contactDetails": 
        "city": null,
        "country": "BE",
        "email": null,
        "extraAddressInfo": null,
        "firstName": null,
        "kboNumber": null,
        "lastName": "TMVW",
        "number": null,
        "organisation": "TMVW - Brugge-Kust",
        "phoneNumber1": null,
        "phoneNumber2": null,
        "postalCode": null,
        "street": null
    ,
    "contractor": null,
    "description": "WEGENISWERKEN - Oostende - 154-W - H Baelskaai-project Oosteroever",
    "diversions": [],
    "endDateTime": "2021-06-30T00:00:00",
    "gipodId": 1042078,
    "hindrance": 
        "description": null,
        "direction": null,
        "effects": [
            "Omleiding: beide richtingen",
            "Afgesloten: volledige rijweg",
            "Fietsers hebben geen doorgang",
            "Handelaars bereikbaar",
            "Plaatselijk verkeer: toegelaten",
            "Voetgangers hebben doorgang"
        ],
        "important": true,
        "locations": [
            "Voetpad",
            "Fietspad",
            "Parkeerstrook",
            "Rijbaan"
        ]
    ,
    "latestUpdate": "2020-12-01T12:16:00.03",
    "location": 
        "cities": [
            "Oostende"
        ],
        "coordinate": 
            "coordinates": [
                2.931988215468502,
                51.23633810341717
            ],
            "crs": 
                "properties": 
                    "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
                ,
                "type": "name"
            ,
            "type": "Point"
        ,
        "geometry": 
            "coordinates": [
                [
                    [
                        2.932567101705748,
                        51.23657315009855
                    ],
                    [
                        2.9309934586397337,
                        51.235776874431004
                    ],
                    [
                        2.9328606392338914,
                        51.2345112414401
                    ],
                    [
                        2.9344086040607285,
                        51.23535468563417
                    ],
                    [
                        2.9344709862243095,
                        51.23529463700852
                    ],
                    [
                        2.932928489694045,
                        51.23447026126373
                    ],
                    [
                        2.935453674897618,
                        51.2326691257775
                    ],
                    [
                        2.937014893295095,
                        51.23347469462423
                    ],
                    [
                        2.9370649363167556,
                        51.23342209549579
                    ],
                    [
                        2.9355339718818847,
                        51.23261689467634
                    ],
                    [
                        2.937705787093551,
                        51.23108125372614
                    ],
                    [
                        2.939235922008332,
                        51.23191301940206
                    ],
                    [
                        2.9393162149112086,
                        51.231860784836144
                    ],
                    [
                        2.9377921292631313,
                        51.23102909334536
                    ],
                    [
                        2.9395494398210404,
                        51.22978103014327
                    ],
                    [
                        2.9395326861153492,
                        51.22973522407282
                    ],
                    [
                        2.9307116955342982,
                        51.23588365892173
                    ],
                    [
                        2.93077732400986,
                        51.235914858980586
                    ],
                    [
                        2.930921969180147,
                        51.23581685905391
                    ],
                    [
                        2.932475593354336,
                        51.23662429379119
                    ],
                    [
                        2.932567101705748,
                        51.23657315009855
                    ]
                ]
            ],
            "crs": 
                "properties": 
                    "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
                ,
                "type": "name"
            ,
            "type": "Polygon"
        
    ,
    "mainContractor": null,
    "owner": "TMVW - Brugge-Kust",
    "reference": "DOM-154/15/004-W",
    "startDateTime": "2017-05-02T00:00:00",
    "state": "In uitvoering",
    "type": "Wegeniswerken (her)aanleg",
    "url": null

提醒一下,这些 JSON 不应该是点文件,并且几何可以是多边形,如上所示:多多边形或多线串(此处没有示例)。

那么我该如何开始,并确保我不仅获得了细节属性,而且还清楚地了解了轮廓几何和坐标?

唯一的唯一 ID 是 GIPOD ID,因为这是此 API 数据库中实际链接所在的位置。

编辑 1:

所以这就是所谓的 geojson 标准。


  "type": "Feature",
  "geometry": 
    "type": "Point",
    "coordinates": [125.6, 10.1]
  ,
  "properties": 
    "name": "Dinagat Islands"
  

根据这个标准,转换后的JSON应该是这样的:

    "type": "Feature",
               "geometry": 
                   "type": "Polygon",
                   "coordinates": [
                    [
                        [
                            2.932567101705748,
                            51.23657315009855
                        ],
                        [
                            2.9309934586397337,
                            51.235776874431004
                        ],
                        [
                            2.9328606392338914,
                            51.2345112414401
                        ],
                        [
                            2.9344086040607285,
                            51.23535468563417
                        ],
                        [
                            2.9344709862243095,
                            51.23529463700852
                        ],
                        [
                            2.932928489694045,
                            51.23447026126373
                        ],
                        [
                            2.935453674897618,
                            51.2326691257775
                        ],
                        [
                            2.937014893295095,
                            51.23347469462423
                        ],
                        [
                            2.9370649363167556,
                            51.23342209549579
                        ],
                        [
                            2.9355339718818847,
                            51.23261689467634
                        ],
                        [
                            2.937705787093551,
                            51.23108125372614
                        ],
                        [
                            2.939235922008332,
                            51.23191301940206
                        ],
                        [
                            2.9393162149112086,
                            51.231860784836144
                        ],
                        [
                            2.9377921292631313,
                            51.23102909334536
                        ],
                        [
                            2.9395494398210404,
                            51.22978103014327
                        ],
                        [
                            2.9395326861153492,
                            51.22973522407282
                        ],
                        [
                            2.9307116955342982,
                            51.23588365892173
                        ],
                        [
                            2.93077732400986,
                            51.235914858980586
                        ],
                        [
                            2.930921969180147,
                            51.23581685905391
                        ],
                        [
                            2.932475593354336,
                            51.23662429379119
                        ],
                        [
                            2.932567101705748,
                            51.23657315009855
                        ]
                   ]
               ,
               "properties": 
Too much columns to type, cannot claim them all here because of character limit.
                   
           

编辑 3:提供的解决方案是朝着正确方向迈出的良好一步,但它给我带来了两个问题:

    保存的几何是 Null,使这个 JSON 成为一个没有 几何。 仅保存 1 个数据点,而不是所有已保存的数据点 正在请求中。

这是 JSON:

"type": "FeatureCollection", "features": ["type": "Feature", "geometry": null, "properties": "gipodId": 3099549, "StartDateTime": null, "EndDateTime": null, "state": null, "location": "cities": ["Waregem", "Wielsbeke"], "coordinate": "coordinates": [3.4206971887218445, 50.91662742195287], "type": "Point", "crs": "type": "name", "properties": "name": "urn:ogc:def:crs:OGC:1.3:CRS84"]

Python 代码:下面看看它已经走了多远:

import requests
import json
import os
import glob
import shutil

def process_location_data(location_json): 
   """Converts the data point into required geojson format"""

  
   # assigning variable to store geometry details
   geometery_details = location_json.get("location").get("geometery")
   #geometery_details.pop("crs")  # removes the "crs" from geometry

   # includes city and location_coordinates
   location_details = 
     "cities": location_json.get("location").get("cities"),
     "coordinate": location_json.get("location").get("coordinate")
   

   #EndDateTime
   end_datetime = location_json.get("EndDateTime")

   #StarDateTime
   start_datetime = location_json.get("StarDateTime")

   #State
   state = location_json.get("State")

   #gipodId
   gipod_id = location_json.get("gipodId")
   
   #adding all these details into another dict
   properties = 
     "gipodId": gipod_id,
     "StartDateTime": start_datetime,
     "EndDateTime": end_datetime,
     "state": state,
     "location": location_details
   


   # creating the final dict to be returned.
   geojson_data_point = 
       "type": "Feature",
       "geometry" : geometery_details,
       "properties": properties
   

   return geojson_data_point

def process_all_location_data(all_location_points):
    """
    For all the points in the location details we will  
    create the feature collection
    """

    feature_collection = 
         "type": "FeatureCollection",
         "features": []
     #creates dict with zero features.

    for data_point in all_location_points:
        feature_collection.get("features").append(
            process_location_data(data_point)
        )

    return feature_collection


def fetch_details(url: str, file_name: str):
      # Makes request call to get the data of detail
        response = requests.get(url)
        print("Sending Request for details of gpodId: " + file_name)
        folder_path ='api_request_jsons/fetch_details/JSON unfiltered'
        text = json.dumps(response.json(),sort_keys=False, indent=4)
        print("Details extracted for: "+ file_name)
        save_file(folder_path,file_name,text)
        return response.json()
        # save_file(folder_path,GipodId,text2)
        # any other processe

def fetch_points(url: str):
       response = requests.get(url)
       folder_path ='api_request_jsons/fetch_points'
       text = json.dumps(response.json(),sort_keys=False, indent=4)
       print("Points Fetched, going to next step: Extracting details")
       for obj in response.json():
         all_location_points = [fetch_details(obj.get("detail"),str(obj.get("gipodId")))]
       save_file(folder_path,'points',text)
       feature_collection_json = process_all_location_data(all_location_points)
       text2 = json.dumps(process_all_location_data(all_location_points))
       folder_path2 = "api_request_jsons/fetch_details/Coordinates"
       file_name2 = "Converted"
       save_file(folder_path2,file_name2,text2)
       return feature_collection_json

def save_file(save_path: str, file_name: str, file_information: str):
        completeName = os.path.join(save_path, file_name +".json")
        print(completeName + " saved")
        file1 = open(completeName, "wt")
        file1.write(file_information)
        file1.close()

api_response_url = "http://api.gipod.vlaanderen.be/ws/v1/workassignment"
fetch_points(api_response_url)

【问题讨论】:

嗨,Joerie,让我试着了解一下挑战。这里你想只提取每个数据点的位置键形式json,还是只提取位置的几何形状? 如果可能的话,位置和几何形状,更不用说稍后在 QGIS 中翻译的其他属性。它只需要在 QGIS 中可读(在 GeoJSON 中转换),包括其他属性和属性。如果这太难了,可以将非位置日期拆分为单独的 CSV 文件,稍后通过唯一 GIODID 加入它们。最佳场景、位置坐标、几何、StarDateTime、EndDateTime 和状态。生成 GeoJSON。 不同特征集合中的位置坐标和几何形状或相同?我对geo json没有经验。你能分享一个预期结果的样本吗?如果我有这些供参考,我将能够更有效地提供帮助。 正如我在 Polygon/MultiPolygon/MultiString 的几何和位置之前所述。一会儿为它“应该看起来”如何创建一个例子。基于 Geojson 标准。 【参考方案1】:

您可以创建另一个函数并将数据传递给它。

# assuming you got the list of points
# and it's stored in all_location_points 

def process_location_data(location_json): 
   """Converts the data point into required geojson format"""
  
   # assigning variable to store geometry details
   geometery_details = location_json.get("location").get("geometery")
   geometery_details.pop("crs")  # removes the "crs" from geometry

   # includes city and location_coordinates
   location_details = 
     "cities": location_json.get("location").get("cities"),
     "coordinate": location_json.get("location").get("coordinate")
   

   #EndDateTime
   end_datetime = location_json.get("EndDateTime")

   #StarDateTime
   start_datetime = location_json.get("StarDateTime")

   #State
   state = location_json.get("State")

   #gipodId
   gipood_id = location_json.get("gipodId")
   
   #adding all these details into another dict
   properties = 
     "gipodId": gipood_id,
     "StartDateTime": start_datetime,
     "EndDateTime": end_datetime,
     "state": state,
     "location": location_details
   


   # creating the final dict to be returned.
   geojson_data_point = 
       "type": "Feature",
       "geometry" : geometery_details,
       "properties": properties
    

   return geojson_data_point


def process_all_location_data(all_location_points):
    """
    For all the points in the location details we will  
    create the feature collection
    """

    feature_collection = 
         "type": "FeatureCollection",
         "features": []
     #creates dict with zero features.

    for data_point in all_location_points:
        feature_collection.get("features").append(
            process_location_data(data_point)
        )

    return feature_collection

参考API Request within another API request (Same API) in Python,可以把这个函数当作


def fetch_details(url: str):
      """
      Makes request call to get the data of detail
     (updated to return details)
      """
      response = requests.get(url)
      return response.json()
       

def fetch_points(url: str):
     """
     Updating this function to fetch and process all points
     and convert them to json
     """
      
       
     response = requests.get(url)
     # shot hand to create list of all the detail points
     all_location_points = [
        fetch_details(obj.get("detail")) for obj in response.json()
     ]

     feature_collection_json = process_all_location_data(all_location_points)
     return feature_colkection_json

api_url = "api.gipod.vlaanderen.be/ws/v1/workassignment"
fetch_points(api_url)

编辑 4:虽然 JSON 最终转换为似乎接近 GeoJSON 标准 RFC 7946 的内容。

https://www.rfc-editor.org/rfc/rfc7946

您应该做一件事将其转换为 QGIS 可以读取的内容。

【讨论】:

我很遗憾地在 all_location_points = [fetch_details(obj.get("detail")) for obj in resonse.json()] 部分得到一个错误,事情是 Repl。它没有告诉我什么错误是,只是强调这是问题所在。 别介意最后一部分我可以确认代码可以通过一些修改来工作,虽然这个设置很棒,但我很难弄清楚如何将这些 GeoJSON 保存在单独的文件中。这将是一个单独的问题。 您的代码很棒,但我遇到了一些新问题,请参阅我的上次编辑。 该死。是的,我看到了这些问题。主要是因为我的错别字。我正在添加一个带有完整解决方案的新答案。【参考方案2】:

根据问题的#Edit 3,我更新了完整的解决方案。有两个问题。

函数process_location_data 中的错字。在这个函数中,我加载的是geometery 而不是geometry(检查拼写错误)

       # incorrect for code
       geometery_details = location_json.get("location").get("geometery")
    
       # correct one
       geometery_details = location_json.get("location").get("geometry")

另外,我在对象的 stateendDateTimestartDateTime 键中发现了拼写错误。 (在下面提供的完整解决方案中修复)

fetch_points 函数中附加列表all_location_points

    #Current code
    for obj in response.json():                                                                                               
        all_location_points = [                                                                                               
            fetch_details(obj.get("detail"), str(obj.get("gipodId")))                                                            
        ]            

在此all_location_points 每次都使用obj 进行更新,而不是将其附加到列表中。

# Fixed 

    all_location_points = []                                                                                                  
    for obj in response.json():                                                                                               
        all_location_points.append(                                                                                           
            fetch_details(obj.get("detail"), str(obj.get("gipodId")))                                                            
        )    

在上面的答案中,我使用速记来创建列表(列表理解)。以上3行可以转换为一行

    all_location_points = [
      fetch_details(obj.get("detail"), str(obj.get("gipodId")))
      for obj in response.json()
    ]

完整的更新解决方案,(包括错字修复和附加列表)


    import requests
    import json
    import os
    import glob
    import shutil
    
    
    def process_location_data(location_json):
        """Converts the data point into required geojson format"""
    
        # assigning variable to store geometry details
        geometery_details = location_json.get("location").get("geometry")
        # geometery_details.pop("crs")  # removes the "crs" from geometry
    
        # includes city and location_coordinates
        location_details = 
            "cities": location_json.get("location").get("cities"),
            "coordinate": location_json.get("location").get("coordinate"),
        
    
        # EndDateTime
        end_datetime = location_json.get("endDateTime")
    
        # StarDateTime
        start_datetime = location_json.get("startDateTime")
    
        # State
        state = location_json.get("state")
    
        # gipodId
        gipod_id = location_json.get("gipodId")
    
        # adding all these details into another dict
        properties = 
            "gipodId": gipod_id,
            "StartDateTime": start_datetime,
            "EndDateTime": end_datetime,
            "state": state,
            "location": location_details,
        
    
        # creating the final dict to be returned.
        geojson_data_point = 
            "type": "Feature",
            "geometry": geometery_details,
            "properties": properties,
        
    
        return geojson_data_point
    
    
    def process_all_location_data(all_location_points):
        """
        For all the points in the location details we will
        create the feature collection
        """
    
        feature_collection = 
            "type": "FeatureCollection",
            "features": [],
          # creates dict with zero features.
    
        for data_point in all_location_points:
            feature_collection.get("features").append(process_location_data(data_point))
    
        return feature_collection
    
    
    def fetch_details(url: str, file_name: str):
        # Makes request call to get the data of detail
        response = requests.get(url)
        print("Sending Request for details of gpodId: " + file_name)
        folder_path = "api_request_jsons/fetch_details/JSON unfiltered"
        text = json.dumps(response.json(), sort_keys=False, indent=4)
        print("Details extracted for: " + file_name)
        save_file(folder_path, file_name, text)
        return response.json()
        # save_file(folder_path,GipodId,text2)
        # any other processe
    
    
    def fetch_points(url: str):
        response = requests.get(url)
        folder_path = "api_request_jsons/fetch_points"
        text = json.dumps(response.json(), sort_keys=False, indent=4)
        print("Points Fetched, going to next step: Extracting details")
        all_location_points = []
        for obj in response.json():
            all_location_points.append(
                fetch_details(obj.get("detail"), str(obj.get("gipodId")))
            )
        save_file(folder_path, "points", text)
        feature_collection_json = process_all_location_data(all_location_points)
        text2 = json.dumps(process_all_location_data(all_location_points))
        folder_path2 = "api_request_jsons/fetch_details/Coordinates"
        file_name2 = "Converted"
        save_file(folder_path2, file_name2, text2)
        return feature_collection_json
    
    
    def save_file(save_path: str, file_name: str, file_information: str):
        completeName = os.path.join(save_path, file_name + ".json")
        print(completeName + " saved")
        file1 = open(completeName, "wt")
        file1.write(file_information)
        file1.close()
    
    
    api_response_url = "http://api.gipod.vlaanderen.be/ws/v1/workassignment"
    fetch_points(api_response_url)

【讨论】:

好的,现在一切正常,但问题是 QGIS,仍然拒绝正确加载它。它仍然是一张没有几何图形且只有一个对象的表格。我想我知道问题出在哪里,但我需要在另一个论坛中询问以确认它,因为这是一个与 GIS 相关的主题。 分享您遇到的错误。或许我可以帮你解决这个问题 确实没有错误,但我可以给你一些截图来说明我的意思。数据似乎并不是以应有的方式加载的正确格式。给我10分钟。 我找到了解决我的问题的方法......显然我需要引入和 Indent = 4 。进入我的 JSON 转储,然后它被识别为一件事,虽然代码不错,但考虑到我缺少的其他属性。我可能需要扩展此代码。谢谢你。还需要稍后添加一些检查。因为我需要检查特征数量是否正确,所以我可以在循环中轻松检查。再次感谢您。 很高兴知道您找到了解决方案。我们听说要互相帮助。如有任何疑问,请随时提出

以上是关于将 JSON 转换为 QGIS GeoJSON:同时具有多种功能和不同类型的主要内容,如果未能解决你的问题,请参考以下文章

QGIS入门实战精品教程004:如何将矢量数据转为GeoJSON格式?

ArcGIS风暴如何将矢量数据(点线面)折点坐标转为GeoJSON格式?

ArcGIS风暴如何将矢量数据(点线面)折点坐标转为GeoJSON格式?

将 geoJson 数据转换为 sql server 空间数据类型(GIS)

shp与geojson格式互转

在 GeoJson 对象中包含 JSON 流?