TopoJSON è una codifica compatta dei dati geografici, ed è comune che ogni feature in un file TopoJSON contenga un oggetto attributo anziché un semplice insieme di coppie chiave‑valore. Esportare quella struttura in CSV è dove di solito le cose vanno storte: la maggior parte degli strumenti o elimina l’oggetto annidato o lo restituisce come stringa JSON inserita in un’unica cella. Questa guida mostra come convertire TopoJSON in CSV in C# usando Aspose.GIS, mantenendo ogni attributo indirizzabile come sua colonna e, facoltativamente, scrivendo la geometria accanto ad essa come Well‑Known Text.

Il vantaggio è che un dataset GIS gerarchico diventa una tabella piatta che SQL Server, Power BI, pandas o un semplice foglio di calcolo possono consumare direttamente, senza alcuno strato di parsing JSON personalizzato nella tua applicazione.

Perché convertire TopoJSON in CSV usando Aspose.GIS

Considera una feature TopoJSON le cui proprietà appaiono così:

{
  "name": "North District",
  "prop1": { "this": "that" }
}

Un writer CSV ingenuo ha tre opzioni sbagliate: scartare prop1, serializzarlo come {"this":"that"} in una singola cella, o fallire. Tutte e tre spostano il problema a valle, dove qualcuno deve rieseguire il parsing del JSON da una colonna di testo prima di poter filtrare o fare join su di esso.

Aspose.GIS adotta un approccio diverso. Quando il driver TopoJSON legge il file, proietta l’oggetto annidato nello schema del layer come un attributo piatto denominato in base al suo percorso, unendo genitore e figlio con un trattino basso. La funzionalità sopra è esposta come due colonne ordinarie:

ColonnaValore
nameDistretto Nord
prop1_thisquello

Poiché l’appiattimento avviene al momento della lettura, la fase di conversione non richiede alcuna gestione speciale. Qualunque cosa il layer esponga è ciò che viene scritto, quindi prop1_this finisce nel CSV come una colonna di prima classe su cui è possibile ordinare, filtrare e fare join.

Prerequisiti per la conversione da TopoJSON a CSV

  • .NET 6.0 o versioni successive, oppure .NET Framework 4.6.2 o versioni successive
  • Aspose.GIS for .NET, installato da NuGet
  • Un file TopoJSON contenente almeno un oggetto attributo annidato

Installa il pacchetto con la CLI .NET:

dotnet add package Aspose.GIS

Oppure dalla Package Manager Console:

Install-Package Aspose.GIS

Un dettaglio di denominazione sorprende le persone: il pacchetto NuGet e l’assembly si chiamano Aspose.GIS, ma lo spazio dei nomi radice è Aspose.Gis con un is minuscolo. Le opzioni del driver CSV si trovano in Aspose.Gis.Formats.Csv.

using Aspose.Gis;
using Aspose.Gis.Formats.Csv;

I dettagli del prodotto sono disponibili nella pagina del prodotto Aspose.GIS for .NET, con l’elenco completo dei tipi nella riferimento API.

Ispeziona lo Schema Appiattito Prima di Convertire

Cosa otterrai: Apri il livello TopoJSON e stampa i nomi degli attributi in modo da sapere esattamente quali colonne conterrà il CSV.

Questo passaggio vale la pena eseguirlo una volta su un file rappresentativo. Ti indica i nomi reali delle colonne generati dall’appiattimento, il che è molto più affidabile rispetto a indovinare a partire dal JSON grezzo.

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})");
    }
}

Per la funzionalità di esempio mostrata in precedenza, questo stampa name (String) e prop1_this (String). L’oggetto annidato non appare mai come attributo a sé stante, il che è esattamente quello che desideri.


Converti TopoJSON in CSV preservando gli attributi nidificati

Cosa otterrai: Carica un file TopoJSON, scrivi ogni attributo appiattito in un file CSV e leggi il risultato per confermare che la colonna sia stata trasferita.

Processo passo-passo

  1. Definisci il percorso TopoJSON di origine e il percorso CSV di destinazione.
  2. Apri l’origine con VectorLayer.Open e conferma che l’attributo appiattito esiste.
  3. Chiama il sovraccarico statico VectorLayer.Convert con i driver di origine e destinazione.
  4. Riapri il CSV con Drivers.Csv e controlla il conteggio delle colonne e i valori.

Il seguente esempio converte un file TopoJSON in CSV, appiattendo le proprietà nidificate lungo il percorso.

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}");
        }
    }
}

Spiegazione

  • VectorLayer.Open(string, FileDriver) apre il file in sola lettura. Drivers.TopoJson restituisce il driver per il formato TopoJSON.
  • FeatureAttributeCollection.Contains(string) è il modo più semplice per verificare la presenza di una colonna per nome. IndexOf ti fornisce la sua posizione se ne hai bisogno.
  • VectorLayer.Convert(string, FileDriver, string, FileDriver) è un helper statico che trasmette la sorgente nel formato di destinazione in una sola chiamata. Esiste anche una sovraccarico che accetta ConversionOptions, utilizzata nella sezione successiva.
  • Feature.GetValue<T>(string) legge un valore di attributo tipizzato. Usa GetValueOrDefault<T>(string) quando una colonna può mancare o essere nulla, poiché GetValue<T> presume che il valore sia presente.
  • Il controllo finale è quello che sorprende le persone. Un file CSV non ha una colonna geometrica a meno che non ne crei una, quindi ogni feature ritorna con una geometria vuota. Questo è il comportamento predefinito, non un errore di conversione, e la sezione successiva lo risolve.

Avvolgere entrambi gli strati in blocchi using è importante qui: VectorLayer implementa IDisposable e il file di destinazione non è garantito di essere svuotato e chiuso finché non viene eliminato.

Includi la geometria come WKT usando CsvOptions

Cosa otterrai: Produce un CSV che contiene sia gli attributi appiattiti e una colonna che contiene la geometria di ciascuna feature come Well-Known Text.

Processo passo-passo

  1. Crea un’istanza di CsvOptions e imposta ColumnWkt sul nome della colonna scelto.
  2. Assegnala a ConversionOptions.DestinationDriverOptions.
  3. Chiama la sovraccarico VectorLayer.Convert che accetta le opzioni di conversione.
  4. Riapri il CSV con gli stessi CsvOptions in modo che il driver sappia quale colonna analizzare come geometria.
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}");
            }
        }
    }
}

Spiegazione

  • CsvOptions.ColumnWkt assegna il nome alla colonna che contiene la geometria di ogni feature in forma WKT. Il valore predefinito è null, e lasciarlo null o vuoto è esattamente il motivo per cui l’esempio precedente non ha prodotto alcuna geometria.
  • ConversionOptions.DestinationDriverOptions è tipizzato come DriverOptions, la classe base per l’oggetto delle impostazioni di ogni driver. Passare un CsvOptions quando il driver di destinazione è Drivers.Csv è ciò che fa sì che l’impostazione abbia effetto; passare opzioni del tipo errato per un driver genera un ArgumentException.
  • La stessa istanza di CsvOptions viene riutilizzata nella fase di lettura. Senza di essa, il driver CSV non ha alcuna ragione di trattare GeometryWkt come qualcosa di diverso da un’altra colonna di tipo stringa.
  • IGeometry.AsText() restituisce la rappresentazione ISO WKT, quindi l’output stampato corrisponde a quanto è stato scritto nel file.

La simmetria è il punto: le colonne di attributi si comportano identicamente sia che la geometria sia inclusa sia che non lo sia, quindi puoi attivare e disattivare la colonna WKT senza toccare il resto della tua pipeline.

Riproiezione durante la conversione

Se il sistema di destinazione si aspetta un sistema di coordinate specifico, richiedilo come parte della conversione anziché elaborare il CSV in post‑processo. ConversionOptions contiene un riferimento spaziale insieme alle opzioni del driver:

var conversionOptions = new ConversionOptions
{
    DestinationDriverOptions = new CsvOptions { ColumnWkt = "GeometryWkt" },
    DestinationSpatialReferenceSystem = SpatialReferenceSystem.Wgs84
};

VectorLayer.Convert(sourcePath, Drivers.TopoJson, destinationPath, Drivers.Csv, conversionOptions);

Non tutti i driver di destinazione supportano tutti i sistemi di riferimento spaziale. Chiama Drivers.Csv.SupportsSpatialReferenceSystem(...) per primo se il sistema di destinazione è configurabile a runtime e ricorri a un oggetto di opzioni null quando non è supportato.

Conversione batch di una cartella di file TopoJSON

L’API è identica per un file e per mille. L’unica regola da ricordare quando si parallelizza è che ogni worker ha bisogno dei propri oggetti layer e options.

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}");
        }
    });
}

Catturare GisException per file anziché intorno all’intero ciclo significa che un file TopoJSON malformato registra un avviso invece di interrompere il batch.

Ottieni una licenza gratuita

Aspose.GIS funziona in modalità di valutazione finché non viene applicata una licenza. Richiedi una licenza temporanea gratuita dalla pagina di licenza temporanea di Aspose e applicala una volta all’avvio dell’applicazione, prima di qualsiasi altra chiamata Aspose.GIS:

var license = new Aspose.Gis.License();
license.SetLicense("Aspose.GIS.NET.lic");

Risorse aggiuntive gratuite

Conclusione

Convertire TopoJSON con proprietà annidate in CSV in .NET si riduce a un comportamento utile: Aspose.GIS appiattisce gli oggetti attributo annidati in colonne nominate come prop1_this mentre il layer viene letto, quindi VectorLayer.Convert non richiede logica personalizzata per preservarli. Aggiungi CsvOptions.ColumnWkt quando il sistema a valle necessita della geometria, aggiungi DestinationSpatialReferenceSystem quando serve una proiezione specifica, e ripeti la stessa chiamata quando devi elaborare una cartella. Il risultato è una tabella piatta, pronta per l’analisi, prodotta da poche righe di C#, senza dover mantenere uno strato di parsing JSON proprio.

FAQs

  1. Aspose.GIS può appiattire oggetti JSON nidificati durante la conversione in CSV? Sì. Il driver TopoJSON espone un oggetto attributo nidificato come colonne separate quando il layer viene aperto, unendo i nomi dei genitori e dei figli con un trattino basso, quindi l’appiattimento è già effettuato prima dell’esecuzione della conversione.

  2. Devo scrivere del codice personalizzato per gestire le proprietà nidificate? No. VectorLayer.Convert scrive tutte le colonne che il layer di origine espone, quindi le proprietà nidificate non richiedono alcun codice di parsing aggiuntivo da parte tua.

  3. Come posso includere la geometria nell’output CSV? Crea un’istanza di CsvOptions, imposta la sua proprietà ColumnWkt sul nome della colonna desiderata, assegnala a ConversionOptions.DestinationDriverOptions e passala a VectorLayer.Convert.

  4. Perché la geometria è vuota quando leggo il mio CSV? Un CSV non ha una colonna geometria a meno che non la richiedi. Imposta ColumnWkt su CsvOptions che passi sia durante la scrittura sia durante la lettura, altrimenti il driver non ha alcuna colonna da cui costruire una geometria.

  5. Quali eccezioni dovrei gestire durante la conversione? Le eccezioni documentate sono ArgumentNullException per un percorso nullo, ArgumentException quando un oggetto di opzioni non corrisponde al driver, GisException quando una funzionalità non può essere letta dal file e IOException per errori di I/O sottostanti.

  6. Posso convertire un batch di file TopoJSON tutti in una volta? Sì. Scorri l’elenco dei file e chiama VectorLayer.Convert per ciascun file. Se parallelizzi il ciclo, assegna a ogni worker la propria istanza di VectorLayer e delle opzioni anziché condividere un’unica istanza tra i thread.

  7. La conversione cambia il sistema di coordinate? Non per impostazione predefinita. Per riproiettare durante la conversione, impostare ConversionOptions.DestinationSpatialReferenceSystem sul sistema di destinazione prima di chiamare Convert.

Leggi di più