TopoJSON là một định dạng mã hoá gọn gàng của dữ liệu địa lý, và thường mỗi tính năng trong tệp TopoJSON sẽ mang một đối tượng thuộc tính thay vì một tập hợp phẳng các cặp khóa-giá trị. Xuất cấu trúc đó sang CSV là nơi thường gặp lỗi: hầu hết các công cụ hoặc bỏ qua đối tượng lồng nhau hoặc đổ nó ra dưới dạng chuỗi JSON được chèn vào một ô duy nhất. Hướng dẫn này cho thấy cách chuyển đổi TopoJSON sang CSV trong C# bằng cách sử dụng Aspose.GIS, giữ cho mỗi thuộc tính có thể truy cập được như một cột riêng và tùy chọn ghi geometry kèm theo dưới dạng Well-Known Text.
Kết quả là một bộ dữ liệu GIS phân cấp trở thành một bảng phẳng mà SQL Server, Power BI, pandas hoặc một bảng tính thông thường có thể tiêu thụ trực tiếp, mà không cần lớp phân tích JSON tùy chỉnh trong ứng dụng của bạn.
Tại sao chuyển đổi TopoJSON sang CSV bằng Aspose.GIS
Xem xét một tính năng TopoJSON có các thuộc tính trông như sau:
{
"name": "North District",
"prop1": { "this": "that" }
}
Một trình ghi CSV ngây thơ có ba tùy chọn tồi: bỏ qua prop1, tuần tự hoá nó thành {"this":"that"} vào một ô, hoặc thất bại. Cả ba đều đẩy vấn đề xuống downstream, nơi ai đó phải phân tích lại JSON từ một cột văn bản trước khi họ có thể lọc hoặc thực hiện join trên nó.
Aspose.GIS có cách tiếp cận khác. Khi trình điều khiển TopoJSON đọc tệp, nó chiếu đối tượng lồng nhau vào sơ đồ lớp dưới dạng một thuộc tính phẳng có tên dựa trên đường dẫn của nó, kết hợp phần cha và con bằng dấu gạch dưới. Tính năng trên được hiển thị dưới dạng hai cột thông thường:
| Cột | Giá trị |
|---|---|
name | Quận Bắc |
prop1_this | đó |
Vì quá trình làm phẳng diễn ra khi đọc, bước chuyển đổi không cần bất kỳ xử lý đặc biệt nào. Bất cứ gì lớp này cung cấp sẽ được ghi lại, vì vậy prop1_this sẽ xuất hiện trong CSV như một cột cấp một mà bạn có thể sắp xếp, lọc và thực hiện phép nối.
Các yêu cầu trước khi chuyển đổi TopoJSON sang CSV
- .NET 6.0 hoặc sau này, hoặc .NET Framework 4.6.2 hoặc sau này
- Aspose.GIS for .NET, được cài đặt từ NuGet
- Một tệp TopoJSON chứa ít nhất một đối tượng thuộc tính lồng nhau
Cài đặt gói bằng .NET CLI:
dotnet add package Aspose.GIS
Hoặc từ Package Manager Console:
Install-Package Aspose.GIS
Một chi tiết đặt tên khiến mọi người bối rối: gói NuGet và assembly được gọi là Aspose.GIS, nhưng không gian tên gốc là Aspose.Gis với chữ is viết thường. Các tùy chọn trình điều khiển CSV nằm trong Aspose.Gis.Formats.Csv.
using Aspose.Gis;
using Aspose.Gis.Formats.Csv;
Chi tiết sản phẩm có trên trang sản phẩm Aspose.GIS for .NET, với danh sách đầy đủ các kiểu trong tài liệu tham chiếu API.
Kiểm tra sơ đồ đã làm phẳng trước khi chuyển đổi
Bạn sẽ đạt được: Mở lớp TopoJSON và in ra tên các thuộc tính của nó để bạn biết chính xác các cột mà CSV sẽ chứa.
Bước này đáng thực hiện một lần trên một tệp đại diện. Nó cho bạn biết các tên cột thực tế được tạo ra sau khi làm phẳng, điều này đáng tin cậy hơn nhiều so với việc đoán chúng từ JSON thô.
using System;
using Aspose.Gis;
using (VectorLayer layer = VectorLayer.Open("data/regions.topojson", Drivers.TopoJson))
{
Console.WriteLine($"Features: {layer.Count}");
foreach (FeatureAttribute attribute in layer.Attributes)
{
Console.WriteLine($" {attribute.Name} ({attribute.DataType})");
}
}
Đối với tính năng mẫu được hiển thị ở trên, điều này sẽ in name (String) và prop1_this (String). Đối tượng lồng nhau sẽ không bao giờ xuất hiện như một thuộc tính riêng biệt, điều này chính là những gì bạn muốn.
Chuyển đổi TopoJSON sang CSV trong khi giữ nguyên các thuộc tính lồng nhau
Bạn sẽ đạt được gì: Tải một tệp TopoJSON, ghi mọi thuộc tính đã được làm phẳng vào tệp CSV, và đọc lại kết quả để xác nhận cột đã được chuyển qua.
Quy trình từng bước
- Xác định đường dẫn TopoJSON nguồn và đường dẫn CSV đích.
- Mở nguồn bằng
VectorLayer.Openvà xác nhận thuộc tính đã được làm phẳng tồn tại. - Gọi phương thức tĩnh
VectorLayer.Convertoverload với các driver nguồn và đích. - Mở lại CSV bằng
Drivers.Csvvà kiểm tra số cột và các giá trị.
Ví dụ sau chuyển đổi một tệp TopoJSON sang CSV, đồng thời làm phẳng các thuộc tính lồng nhau trong quá trình.
using System;
using System.IO;
using Aspose.Gis;
class TopoJsonToCsv
{
static void Main()
{
string sourcePath = Path.Combine("data", "regions.topojson");
string destinationPath = Path.Combine("output", "regions.csv");
Directory.CreateDirectory("output");
// Confirm the nested property was flattened when the layer was opened.
using (VectorLayer source = VectorLayer.Open(sourcePath, Drivers.TopoJson))
{
Console.WriteLine($"Source features: {source.Count}");
Console.WriteLine($"Has prop1_this: {source.Attributes.Contains("prop1_this")}");
}
// No options are needed. The conversion writes whatever columns the
// source layer exposes, flattened attributes included.
VectorLayer.Convert(sourcePath, Drivers.TopoJson, destinationPath, Drivers.Csv);
// Read the CSV back and verify the schema survived the round trip.
using (VectorLayer csv = VectorLayer.Open(destinationPath, Drivers.Csv))
{
Console.WriteLine($"Rows: {csv.Count}, Columns: {csv.Attributes.Count}");
if (csv.Attributes.Contains("prop1_this"))
{
Console.WriteLine($"First value: {csv[0].GetValue<string>("prop1_this")}");
}
// No WKT column was requested, so features read back without geometry.
Console.WriteLine($"Geometry empty: {csv[0].Geometry.IsEmpty}");
}
}
}
Giải thích
VectorLayer.Open(string, FileDriver)mở tệp ở chế độ chỉ đọc.Drivers.TopoJsontrả về driver cho định dạng TopoJSON.FeatureAttributeCollection.Contains(string)là cách rẻ nhất để kiểm tra một cột theo tên.IndexOfcung cấp vị trí của nó nếu bạn cần.VectorLayer.Convert(string, FileDriver, string, FileDriver)là một trợ giúp tĩnh giúp truyền luồng nguồn sang định dạng đích trong một lần gọi. Cũng có một overload nhậnConversionOptions, được sử dụng trong phần tiếp theo.Feature.GetValue<T>(string)đọc giá trị thuộc tính có kiểu. Sử dụngGetValueOrDefault<T>(string)khi một cột có thể thiếu hoặc null, vìGetValue<T>giả định giá trị tồn tại.- Kiểm tra cuối cùng là điều khiến mọi người ngạc nhiên. Tệp CSV không có cột geometry trừ khi bạn tạo ra, vì vậy mỗi feature sẽ trả về geometry rỗng. Đó là hành vi mặc định, không phải lỗi chuyển đổi, và phần tiếp theo sẽ khắc phục nó.
Việc bao bọc cả hai lớp trong các khối using là quan trọng ở đây: VectorLayer triển khai IDisposable, và tệp đích không được đảm bảo sẽ được flush và đóng cho đến khi nó được giải phóng.
Bao gồm Geometry dưới dạng WKT bằng CsvOptions
Bạn sẽ đạt được: Tạo một CSV chứa cả các thuộc tính đã được làm phẳng và một cột giữ hình học của mỗi đối tượng dưới dạng Well-Known Text.
Quy trình từng bước
- Tạo một thể hiện
CsvOptionsvà đặtColumnWktthành tên cột bạn chọn. - Gán nó cho
ConversionOptions.DestinationDriverOptions. - Gọi overload
VectorLayer.Convertchấp nhận các tùy chọn chuyển đổi. - Mở lại tệp CSV bằng cùng
CsvOptionsđể driver biết cột nào sẽ được phân tích như hình học.
using System;
using System.IO;
using Aspose.Gis;
using Aspose.Gis.Formats.Csv;
class TopoJsonToCsvWithGeometry
{
static void Main()
{
string sourcePath = Path.Combine("data", "regions.topojson");
string destinationPath = Path.Combine("output", "regions-wkt.csv");
Directory.CreateDirectory("output");
// Ask the CSV driver for a geometry column named "GeometryWkt".
var csvOptions = new CsvOptions
{
ColumnWkt = "GeometryWkt"
};
var conversionOptions = new ConversionOptions
{
DestinationDriverOptions = csvOptions
};
VectorLayer.Convert(
sourcePath,
Drivers.TopoJson,
destinationPath,
Drivers.Csv,
conversionOptions);
// Pass the same options when reading, or the WKT column is just text.
using (VectorLayer layer = VectorLayer.Open(destinationPath, Drivers.Csv, csvOptions))
{
foreach (Feature feature in layer)
{
string name = feature.GetValueOrDefault<string>("name");
string wkt = feature.Geometry.IsEmpty ? "(empty)" : feature.Geometry.AsText();
Console.WriteLine($"{name}: {wkt}");
}
}
}
}
Giải thích
CsvOptions.ColumnWktđặt tên cho cột chứa hình học của mỗi đối tượng dưới dạng WKT. Mặc định lànull, và việc để nó null hoặc rỗng chính là lý do ví dụ trước không tạo ra hình học.ConversionOptions.DestinationDriverOptionscó kiểu làDriverOptions, lớp cơ sở cho mọi đối tượng cài đặt của driver. Việc truyền mộtCsvOptionskhi driver đích làDrivers.Csvlà cách để thiết lập có hiệu lực; truyền các tùy chọn sai kiểu cho một driver sẽ gây raArgumentException.- Cùng một thể hiện
CsvOptionsđược tái sử dụng ở phía đọc. Nếu không có nó, driver CSV sẽ không có lý do để xemGeometryWktlà gì khác ngoài một cột chuỗi khác. IGeometry.AsText()trả về biểu diễn ISO WKT, vì vậy đầu ra được in ra khớp với những gì đã được ghi vào tệp.
Sự đối xứng là điểm mấu chốt: các cột thuộc tính hoạt động giống hệt nhau dù có hoặc không có geometry, vì vậy bạn có thể bật và tắt cột WKT mà không ảnh hưởng đến phần còn lại của quy trình xử lý.
Chuyển đổi hệ tọa độ trong quá trình chuyển đổi
Nếu hệ thống tiêu thụ mong đợi một hệ tọa độ cụ thể, hãy yêu cầu nó như một phần của quá trình chuyển đổi thay vì xử lý sau CSV. ConversionOptions mang theo một tham chiếu không gian cùng với các tùy chọn driver:
var conversionOptions = new ConversionOptions
{
DestinationDriverOptions = new CsvOptions { ColumnWkt = "GeometryWkt" },
DestinationSpatialReferenceSystem = SpatialReferenceSystem.Wgs84
};
VectorLayer.Convert(sourcePath, Drivers.TopoJson, destinationPath, Drivers.Csv, conversionOptions);
Không phải mọi driver đích đều hỗ trợ mọi hệ tham chiếu không gian. Hãy gọi Drivers.Csv.SupportsSpatialReferenceSystem(...) trước nếu hệ thống mục tiêu có thể cấu hình tại thời gian chạy, và quay lại một đối tượng tùy chọn null khi nó không được hỗ trợ.
Chuyển đổi Hàng loạt một Thư mục các Tệp TopoJSON
API giống hệt cho một tệp và cho hàng ngàn tệp. Quy tắc duy nhất cần ghi nhớ khi bạn thực hiện song song là mỗi worker cần có lớp và các đối tượng tùy chọn riêng của mình.
using System;
using System.IO;
using System.Threading.Tasks;
using Aspose.Gis;
using Aspose.Gis.Formats.Csv;
static void ConvertFolder(string inputFolder, string outputFolder)
{
Directory.CreateDirectory(outputFolder);
var files = Directory.GetFiles(inputFolder, "*.topojson");
Parallel.ForEach(files, file =>
{
string destination = Path.Combine(
outputFolder,
Path.GetFileNameWithoutExtension(file) + ".csv");
// Fresh options per iteration: nothing is shared across threads.
var options = new ConversionOptions
{
DestinationDriverOptions = new CsvOptions { ColumnWkt = "GeometryWkt" }
};
try
{
VectorLayer.Convert(file, Drivers.TopoJson, destination, Drivers.Csv, options);
}
catch (GisException ex)
{
Console.Error.WriteLine($"Skipped {Path.GetFileName(file)}: {ex.Message}");
}
});
}
Bắt GisException cho từng tệp thay vì bao quanh toàn bộ vòng lặp có nghĩa là một tệp TopoJSON bị hỏng sẽ ghi cảnh báo thay vì dừng quá trình xử lý.
Nhận giấy phép miễn phí
Aspose.GIS chạy ở chế độ đánh giá cho đến khi giấy phép được áp dụng. Yêu cầu một giấy phép tạm thời miễn phí từ trang giấy phép tạm thời của Aspose và áp dụng nó một lần khi khởi động ứng dụng, trước bất kỳ lời gọi Aspose.GIS nào khác:
var license = new Aspose.Gis.License();
license.SetLicense("Aspose.GIS.NET.lic");
Tài nguyên bổ sung miễn phí
Kết luận
Việc chuyển đổi TopoJSON có các thuộc tính lồng nhau sang CSV trong .NET chỉ dựa vào một hành vi hữu ích: Aspose.GIS làm phẳng các đối tượng thuộc tính lồng nhau thành các cột có tên như prop1_this khi lớp đang được đọc, vì vậy VectorLayer.Convert không cần logic tùy chỉnh nào để giữ chúng. Thêm CsvOptions.ColumnWkt khi hệ thống downstream cần hình học, thêm DestinationSpatialReferenceSystem khi nó cần một phép chiếu cụ thể, và lặp lại cùng cuộc gọi khi bạn cần xử lý một thư mục. Kết quả là một bảng phẳng, sẵn sàng cho phân tích được tạo ra chỉ bằng một vài dòng C#, mà không cần lớp phân tích JSON riêng của bạn để duy trì.
Câu hỏi thường gặp
Aspose.GIS có thể làm phẳng các đối tượng JSON lồng nhau khi chuyển sang CSV không? Có. Trình điều khiển TopoJSON hiển thị một đối tượng thuộc tính lồng nhau dưới dạng các cột riêng biệt khi lớp được mở, kết hợp tên cha và con bằng dấu gạch dưới, vì vậy việc làm phẳng đã được thực hiện trước khi quá trình chuyển đổi chạy.
Tôi có cần viết mã tùy chỉnh để xử lý các thuộc tính lồng nhau không? Không.
VectorLayer.Convertghi bất kỳ cột nào mà lớp nguồn cung cấp, vì vậy các thuộc tính lồng nhau không cần mã phân tích bổ sung nào từ phía bạn.Làm thế nào tôi có thể bao gồm geometry trong đầu ra CSV? Tạo một thể hiện
CsvOptions, đặt thuộc tínhColumnWktcủa nó thành tên cột bạn muốn, gán nó choConversionOptions.DestinationDriverOptions, và truyền nó choVectorLayer.Convert.Tại sao geometry lại trống khi tôi đọc lại CSV? Một tệp CSV không có cột geometry trừ khi bạn yêu cầu. Đặt
ColumnWkttrênCsvOptionsmà bạn truyền cả khi ghi và khi đọc, nếu không, driver sẽ không có cột nào để xây dựng geometry.Những ngoại lệ nào tôi nên xử lý trong quá trình chuyển đổi? Các ngoại lệ được tài liệu ghi nhận là
ArgumentNullExceptioncho đường dẫn null,ArgumentExceptionkhi đối tượng tùy chọn không khớp với driver,GisExceptionkhi một tính năng không thể đọc được từ tệp, vàIOExceptioncho các lỗi I/O cơ bản.Tôi có thể chuyển đổi một loạt các tệp TopoJSON cùng một lúc không? Có. Lặp qua danh sách tệp và gọi
VectorLayer.Convertcho mỗi tệp. Nếu bạn thực hiện song song vòng lặp, hãy cung cấp cho mỗi worker một thể hiệnVectorLayervà các tùy chọn riêng thay vì chia sẻ một thể hiện chung giữa các luồng.Quá trình chuyển đổi có thay đổi hệ tọa độ không? Mặc định thì không. Để tái chiếu trong quá trình chuyển đổi, hãy đặt
ConversionOptions.DestinationSpatialReferenceSystemthành hệ mục tiêu trước khi gọiConvert.
