TopoJSON jest zwartym kodowaniem danych geograficznych i powszechnie każdy element w pliku TopoJSON zawiera obiekt atrybutów, a nie płaską listę par klucz‑wartość. Eksportowanie tej struktury do CSV to miejsce, w którym zazwyczaj pojawiają się problemy: większość narzędzi albo usuwa zagnieżdżony obiekt, albo zapisuje go jako ciąg JSON umieszczony w jednej komórce. Ten przewodnik pokazuje jak przekonwertować TopoJSON na CSV w C# przy użyciu Aspose.GIS, zachowując każdy atrybut jako osobną kolumnę i opcjonalnie zapisując geometrię obok niej w formacie Well‑Known Text.
Korzyścią jest to, że hierarchiczny zestaw danych GIS staje się płaską tabelą, którą SQL Server, Power BI, pandas lub zwykły arkusz kalkulacyjny może bezpośrednio wykorzystać, bez potrzeby niestandardowej warstwy parsowania JSON w aplikacji.
Dlaczego konwertować TopoJSON na CSV przy użyciu Aspose.GIS
Rozważmy cechę TopoJSON, której właściwości wyglądają następująco:
{
"name": "North District",
"prop1": { "this": "that" }
}
Naiwny zapis CSV ma trzy złe opcje: pominąć prop1, zserializować go jako {"this":"that"} w jednej komórce lub zakończyć niepowodzeniem. Wszystkie trzy przenoszą problem w dół strumienia, gdzie ktoś musi ponownie sparsować JSON z kolumny tekstowej, zanim będzie mógł filtrować lub łączyć dane.
Aspose.GIS przyjmuje inne podejście. Gdy sterownik TopoJSON odczytuje plik, projektuje zagnieżdżony obiekt do schematu warstwy jako płaski atrybut nazwany po jego ścieżce, łącząc rodzica i dziecko podkreśleniem. Powyższa cecha jest udostępniona jako dwie zwykłe kolumny:
| Kolumna | Wartość |
|---|---|
name | Północny Dystrykt |
prop1_this | to |
Ponieważ spłaszczanie odbywa się w czasie odczytu, krok konwersji nie wymaga żadnego specjalnego przetwarzania. Cokolwiek warstwa udostępnia, jest zapisywane, więc prop1_this trafia do pliku CSV jako pełnoprawna kolumna, którą można sortować, filtrować i łączyć.
Wymagania wstępne konwersji TopoJSON do CSV
- .NET 6.0 lub nowszy, lub .NET Framework 4.6.2 lub nowszy
- Aspose.GIS for .NET, zainstalowany z NuGet
- Plik TopoJSON zawierający co najmniej jeden zagnieżdżony obiekt atrybutów
Zainstaluj pakiet za pomocą .NET CLI:
dotnet add package Aspose.GIS
Lub z konsoli Menedżera pakietów:
Install-Package Aspose.GIS
Jedna szczegółowa kwestia nazewnictwa wprowadza w błąd: pakiet NuGet i zestawienie są nazwane Aspose.GIS, ale główna przestrzeń nazw to Aspose.Gis z małymi literami is. Opcje sterownika CSV znajdują się w Aspose.Gis.Formats.Csv.
using Aspose.Gis;
using Aspose.Gis.Formats.Csv;
Szczegóły produktu znajdują się na stronie produktu Aspose.GIS for .NET, a pełna lista typów jest dostępna w referencji API.
Sprawdź spłaszczony schemat przed konwersją
Co osiągniesz: Otwórz warstwę TopoJSON i wydrukuj nazwy jej atrybutów, aby dokładnie wiedzieć, które kolumny będzie zawierał plik CSV.
Ten krok warto wykonać raz na reprezentatywnym pliku. Informuje o rzeczywistych nazwach kolumn uzyskanych po spłaszczeniu, co jest znacznie bardziej niezawodne niż zgadywanie ich na podstawie surowego JSON.
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})");
}
}
Dla przykładowej funkcji pokazanej wcześniej, to wypisuje name (String) i prop1_this (String). Zagnieżdżony obiekt nigdy nie pojawia się jako atrybut samodzielnie, co jest dokładnie tym, czego chcesz.
Konwertuj TopoJSON na CSV zachowując zagnieżdżone atrybuty
Co osiągniesz: Załaduj plik TopoJSON, zapisz każdy spłaszczony atrybut do pliku CSV i odczytaj wynik, aby potwierdzić, że kolumna przeszła.
Proces krok po kroku
- Zdefiniuj ścieżkę źródłowego pliku TopoJSON oraz ścieżkę docelowego pliku CSV.
- Otwórz źródło za pomocą
VectorLayer.Openi potwierdź, że istnieje spłaszczony atrybut. - Wywołaj statyczne przeciążenie
VectorLayer.Convertz driverami źródłowym i docelowym. - Ponownie otwórz plik CSV za pomocą
Drivers.Csvi sprawdź liczbę kolumn oraz wartości.
Poniższy przykład konwertuje plik TopoJSON na CSV, spłaszczając zagnieżdżone właściwości po drodze.
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}");
}
}
}
Wyjaśnienie
VectorLayer.Open(string, FileDriver)otwiera plik w trybie tylko do odczytu.Drivers.TopoJsonzwraca sterownik dla formatu TopoJSON.FeatureAttributeCollection.Contains(string)jest najtańszym sposobem sprawdzenia, czy istnieje kolumna o danej nazwie.IndexOfpodaje jej pozycję, jeśli jest potrzebna.VectorLayer.Convert(string, FileDriver, string, FileDriver)jest statycznym pomocnikiem, który w jednym wywołaniu przesyła źródło do formatu docelowego. Istnieje także przeciążenie przyjmująceConversionOptions, używane w następnym rozdziale.Feature.GetValue<T>(string)odczytuje wartość atrybutu o określonym typie. UżyjGetValueOrDefault<T>(string), gdy kolumna może być nieobecna lub mieć wartość null, ponieważGetValue<T>zakłada, że wartość jest obecna.- Ostatnie sprawdzenie jest tym, które zaskakuje ludzi. Plik CSV nie ma kolumny geometrii, chyba że ją utworzysz, więc każdy obiekt zwraca pustą geometrię. To jest domyślne zachowanie, a nie błąd konwersji, a kolejny rozdział to naprawia.
Opakowanie obu warstw w bloki using ma tutaj znaczenie: VectorLayer implementuje IDisposable, a plik docelowy nie jest gwarantowany, że zostanie opróżniony i zamknięty, dopóki nie zostanie zwolniony.
Dołącz geometrię jako WKT przy użyciu CsvOptions
Co osiągniesz: Wygeneruj plik CSV, który zawiera zarówno spłaszczone atrybuty oraz kolumnę przechowującą geometrię każdego obiektu w formacie Well-Known Text.
Proces krok po kroku
- Utwórz instancję
CsvOptionsi ustawColumnWktna wybraną nazwę kolumny. - Przypisz ją do
ConversionOptions.DestinationDriverOptions. - Wywołaj przeciążenie
VectorLayer.Convert, które przyjmuje opcje konwersji. - Otwórz ponownie CSV z tymi samymi
CsvOptions, aby sterownik wiedział, którą kolumnę parsować jako geometrię.
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}");
}
}
}
}
Wyjaśnienie
CsvOptions.ColumnWktnazywa kolumnę, w której przechowywana jest geometria każdego obiektu w formacie WKT. Domyślnie ma wartośćnull, a pozostawienie jej jako null lub pustej jest dokładnie powodem, dla którego wcześniejszy przykład nie wygenerował geometrii.ConversionOptions.DestinationDriverOptionsjest typowany jakoDriverOptions, bazowa klasa dla obiektu ustawień każdego sterownika. PrzekazanieCsvOptions, gdy docelowy sterownik toDrivers.Csv, powoduje zastosowanie ustawienia; przekazanie opcji niewłaściwego typu dla sterownika powoduje wyrzucenieArgumentException.- Ta sama instancja
CsvOptionsjest ponownie używana po stronie odczytu. Bez niej sterownik CSV nie ma powodu traktowaćGeometryWktjako innej kolumny typu string. IGeometry.AsText()zwraca reprezentację ISO WKT, więc wydrukowane wyjście odpowiada temu, co zostało zapisane do pliku.
Symetria jest kluczowa: kolumny atrybutów zachowują się identycznie, niezależnie od tego, czy geometria jest uwzględniona, więc możesz włączać i wyłączać kolumnę WKT bez ingerencji w resztę swojego potoku.
Przekształć podczas konwersji
Jeśli system odbierający oczekuje określonego układu współrzędnych, poproś o niego w ramach konwersji, a nie w trakcie przetwarzania CSV. ConversionOptions zawiera odniesienie przestrzenne wraz z opcjami sterownika:
var conversionOptions = new ConversionOptions
{
DestinationDriverOptions = new CsvOptions { ColumnWkt = "GeometryWkt" },
DestinationSpatialReferenceSystem = SpatialReferenceSystem.Wgs84
};
VectorLayer.Convert(sourcePath, Drivers.TopoJson, destinationPath, Drivers.Csv, conversionOptions);
Nie każdy sterownik docelowy obsługuje każdy układ odniesienia przestrzennego. Najpierw wywołaj Drivers.Csv.SupportsSpatialReferenceSystem(...), jeśli docelowy system jest konfigurowalny w czasie wykonywania, i w razie braku wsparcia użyj obiektu opcji o wartości null.
Masowa konwersja folderu plików TopoJSON
API jest identyczne dla jednego pliku i dla tysiąca. Jedyną zasadą, którą warto zapamiętać przy równoległym przetwarzaniu, jest to, że każdy wątek potrzebuje własnych obiektów warstwy i opcji.
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}");
}
});
}
Łapanie GisException dla każdego pliku zamiast wokół całej pętli oznacza, że jeden nieprawidłowy plik TopoJSON zapisuje ostrzeżenie zamiast przerywać wsad.
Uzyskaj darmową licencję
Aspose.GIS działa w trybie ewaluacyjnym, dopóki nie zostanie zastosowana licencja. Poproś o darmową tymczasową licencję na stronie tymczasowej licencji Aspose i zastosuj ją raz przy uruchamianiu aplikacji, przed jakimkolwiek innym wywołaniem Aspose.GIS:
var license = new Aspose.Gis.License();
license.SetLicense("Aspose.GIS.NET.lic");
Darmowe dodatkowe zasoby
Podsumowanie
Konwersja TopoJSON z zagnieżdżonymi właściwościami do CSV w .NET sprowadza się do jednego przydatnego zachowania: Aspose.GIS spłaszcza zagnieżdżone obiekty atrybutów do nazwanych kolumn, takich jak prop1_this, podczas odczytu warstwy, więc VectorLayer.Convert nie wymaga własnej logiki, aby je zachować. Dodaj CsvOptions.ColumnWkt, gdy system downstream potrzebuje geometrii, dodaj DestinationSpatialReferenceSystem, gdy potrzebna jest konkretna projekcja, i powtarzaj to samo wywołanie, gdy musisz przetworzyć folder. Wynikiem jest płaska, gotowa do analizy tabela wygenerowana kilkoma liniami C#, bez konieczności utrzymywania własnej warstwy parsowania JSON.
Najczęściej zadawane pytania
Czy Aspose.GIS może spłaszczyć zagnieżdżone obiekty JSON podczas konwersji do CSV? Tak. Sterownik TopoJSON udostępnia zagnieżdżony obiekt atrybutów jako osobne kolumny po otwarciu warstwy, łącząc nazwy rodzica i dziecka podkreśleniem, więc spłaszczenie jest już wykonane przed uruchomieniem konwersji.
Czy muszę pisać własny kod, aby obsłużyć zagnieżdżone właściwości? Nie.
VectorLayer.Convertzapisuje wszystkie kolumny, które udostępnia warstwa źródłowa, więc zagnieżdżone właściwości nie wymagają dodatkowego kodu parsującego z Twojej strony.Jak mogę uwzględnić geometrię w wyjściu CSV? Utwórz instancję
CsvOptions, ustaw jej właściwośćColumnWktna nazwę kolumny, którą chcesz, przypisz ją doConversionOptions.DestinationDriverOptionsi przekaż ją doVectorLayer.Convert.Dlaczego geometria jest pusta, gdy odczytuję mój CSV?
Plik CSV nie ma kolumny geometrycznej, chyba że ją wyraźnie określisz. UstawColumnWktw obiekcieCsvOptions, który przekazujesz zarówno przy zapisywaniu, jak i przy odczytywaniu, w przeciwnym razie sterownik nie będzie miał kolumny, z której mógłby zbudować geometrię.Jakie wyjątki powinienem obsłużyć podczas konwersji? Udokumentowane to
ArgumentNullExceptiondla pustej ścieżki,ArgumentExceptiongdy obiekt opcji nie pasuje do sterownika,GisExceptiongdy nie można odczytać funkcji z pliku orazIOExceptionw przypadku podstawowych błędów I/O.Czy mogę konwertować paczkę plików TopoJSON jednocześnie? Tak. Przejdź przez listę plików i wywołaj
VectorLayer.Convertdla każdego pliku. Jeśli równolegle wykonujesz pętlę, przydziel każdemu wątkowi własną instancjęVectorLayeri opcji, zamiast udostępniać jedną dla wszystkich wątków.Czy konwersja zmienia układ współrzędnych? Nie domyślnie. Aby przekształcić podczas konwersji, ustaw
ConversionOptions.DestinationSpatialReferenceSystemna docelowy system przed wywołaniemConvert.
