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:

KolumnaWartość
namePółnocny Dystrykt
prop1_thisto

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

  1. Zdefiniuj ścieżkę źródłowego pliku TopoJSON oraz ścieżkę docelowego pliku CSV.
  2. Otwórz źródło za pomocą VectorLayer.Open i potwierdź, że istnieje spłaszczony atrybut.
  3. Wywołaj statyczne przeciążenie VectorLayer.Convert z driverami źródłowym i docelowym.
  4. Ponownie otwórz plik CSV za pomocą Drivers.Csv i 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.TopoJson zwraca sterownik dla formatu TopoJSON.
  • FeatureAttributeCollection.Contains(string) jest najtańszym sposobem sprawdzenia, czy istnieje kolumna o danej nazwie. IndexOf podaje 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ące ConversionOptions, używane w następnym rozdziale.
  • Feature.GetValue<T>(string) odczytuje wartość atrybutu o określonym typie. Użyj GetValueOrDefault<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

  1. Utwórz instancję CsvOptions i ustaw ColumnWkt na wybraną nazwę kolumny.
  2. Przypisz ją do ConversionOptions.DestinationDriverOptions.
  3. Wywołaj przeciążenie VectorLayer.Convert, które przyjmuje opcje konwersji.
  4. 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.ColumnWkt nazywa 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.DestinationDriverOptions jest typowany jako DriverOptions, bazowa klasa dla obiektu ustawień każdego sterownika. Przekazanie CsvOptions, gdy docelowy sterownik to Drivers.Csv, powoduje zastosowanie ustawienia; przekazanie opcji niewłaściwego typu dla sterownika powoduje wyrzucenie ArgumentException.
  • Ta sama instancja CsvOptions jest ponownie używana po stronie odczytu. Bez niej sterownik CSV nie ma powodu traktować GeometryWkt jako 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

  1. 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.

  2. Czy muszę pisać własny kod, aby obsłużyć zagnieżdżone właściwości? Nie. VectorLayer.Convert zapisuje 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.

  3. Jak mogę uwzględnić geometrię w wyjściu CSV? Utwórz instancję CsvOptions, ustaw jej właściwość ColumnWkt na nazwę kolumny, którą chcesz, przypisz ją do ConversionOptions.DestinationDriverOptions i przekaż ją do VectorLayer.Convert.

  4. Dlaczego geometria jest pusta, gdy odczytuję mój CSV?
    Plik CSV nie ma kolumny geometrycznej, chyba że ją wyraźnie określisz. Ustaw ColumnWkt w obiekcie CsvOptions, 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ę.

  5. Jakie wyjątki powinienem obsłużyć podczas konwersji? Udokumentowane to ArgumentNullException dla pustej ścieżki, ArgumentException gdy obiekt opcji nie pasuje do sterownika, GisException gdy nie można odczytać funkcji z pliku oraz IOException w przypadku podstawowych błędów I/O.

  6. Czy mogę konwertować paczkę plików TopoJSON jednocześnie? Tak. Przejdź przez listę plików i wywołaj VectorLayer.Convert dla każdego pliku. Jeśli równolegle wykonujesz pętlę, przydziel każdemu wątkowi własną instancję VectorLayer i opcji, zamiast udostępniać jedną dla wszystkich wątków.

  7. Czy konwersja zmienia układ współrzędnych? Nie domyślnie. Aby przekształcić podczas konwersji, ustaw ConversionOptions.DestinationSpatialReferenceSystem na docelowy system przed wywołaniem Convert.

Czytaj więcej