| 87 | std::string EscapeCrsAsJsonIfRequired(std::string_view crs); |
| 88 | |
| 89 | ::arrow::Result<std::string> MakeGeoArrowCrsMetadata( |
| 90 | std::string_view crs, |
| 91 | const std::shared_ptr<const ::arrow::KeyValueMetadata>& metadata) { |
| 92 | const std::string kSridPrefix{"srid:"}; |
| 93 | const std::string kProjjsonPrefix{"projjson:"}; |
| 94 | |
| 95 | // Two recommendations are explicitly mentioned in the Parquet format for the |
| 96 | // LogicalType crs: |
| 97 | // |
| 98 | // - "srid:XXXX" as a way to encode an application-specific integer identifier |
| 99 | // - "projjson:some_field_name" as a way to avoid repeating PROJJSON strings |
| 100 | // unnecessarily (with a suggestion to place them in the file metadata) |
| 101 | // |
| 102 | // While we don't currently generate those values to reduce the complexity |
| 103 | // of the writer, we do interpret these values according to the suggestion in |
| 104 | // the format and pass on this information to GeoArrow. |
| 105 | if (crs.empty()) { |
| 106 | return R"("crs": "OGC:CRS84", "crs_type": "authority_code")"; |
| 107 | } else if (crs.starts_with(kSridPrefix)) { |
| 108 | return R"("crs": ")" + std::string(crs.substr(kSridPrefix.size())) + |
| 109 | R"(", "crs_type": "srid")"; |
| 110 | } else if (crs.starts_with(kProjjsonPrefix)) { |
| 111 | std::string_view metadata_field = crs.substr(kProjjsonPrefix.size()); |
| 112 | if (metadata && metadata->Contains(metadata_field)) { |
| 113 | ARROW_ASSIGN_OR_RAISE(std::string projjson_value, metadata->Get(metadata_field)); |
| 114 | // This value should be valid JSON, but if it is not, we escape it as a string such |
| 115 | // that it can be inspected by the consumer of GeoArrow. |
| 116 | return R"("crs": )" + EscapeCrsAsJsonIfRequired(projjson_value) + |
| 117 | R"(, "crs_type": "projjson")"; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | // Pass on the string directly to GeoArrow. If the string is already valid JSON, |
| 122 | // insert it directly into GeoArrow's "crs" field. Otherwise, escape it and pass it as a |
| 123 | // string value. |
| 124 | return R"("crs": )" + EscapeCrsAsJsonIfRequired(crs); |
| 125 | } |
| 126 | |
| 127 | std::string EscapeCrsAsJsonIfRequired(std::string_view crs) { |
| 128 | namespace rj = ::arrow::rapidjson; |
nothing calls this directly
no test coverage detected