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:
| Colonna | Valore |
|---|---|
name | Distretto Nord |
prop1_this | quello |
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
- Definisci il percorso TopoJSON di origine e il percorso CSV di destinazione.
- Apri l’origine con
VectorLayer.Opene conferma che l’attributo appiattito esiste. - Chiama il sovraccarico statico
VectorLayer.Convertcon i driver di origine e destinazione. - Riapri il CSV con
Drivers.Csve 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.TopoJsonrestituisce il driver per il formato TopoJSON.FeatureAttributeCollection.Contains(string)è il modo più semplice per verificare la presenza di una colonna per nome.IndexOfti 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 accettaConversionOptions, utilizzata nella sezione successiva.Feature.GetValue<T>(string)legge un valore di attributo tipizzato. UsaGetValueOrDefault<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
- Crea un’istanza di
CsvOptionse impostaColumnWktsul nome della colonna scelto. - Assegnala a
ConversionOptions.DestinationDriverOptions. - Chiama la sovraccarico
VectorLayer.Convertche accetta le opzioni di conversione. - Riapri il CSV con gli stessi
CsvOptionsin 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.ColumnWktassegna 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 comeDriverOptions, la classe base per l’oggetto delle impostazioni di ogni driver. Passare unCsvOptionsquando il driver di destinazione èDrivers.Csvè ciò che fa sì che l’impostazione abbia effetto; passare opzioni del tipo errato per un driver genera unArgumentException.- La stessa istanza di
CsvOptionsviene riutilizzata nella fase di lettura. Senza di essa, il driver CSV non ha alcuna ragione di trattareGeometryWktcome 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
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.
Devo scrivere del codice personalizzato per gestire le proprietà nidificate? No.
VectorLayer.Convertscrive tutte le colonne che il layer di origine espone, quindi le proprietà nidificate non richiedono alcun codice di parsing aggiuntivo da parte tua.Come posso includere la geometria nell’output CSV? Crea un’istanza di
CsvOptions, imposta la sua proprietàColumnWktsul nome della colonna desiderata, assegnala aConversionOptions.DestinationDriverOptionse passala aVectorLayer.Convert.Perché la geometria è vuota quando leggo il mio CSV? Un CSV non ha una colonna geometria a meno che non la richiedi. Imposta
ColumnWktsuCsvOptionsche passi sia durante la scrittura sia durante la lettura, altrimenti il driver non ha alcuna colonna da cui costruire una geometria.Quali eccezioni dovrei gestire durante la conversione? Le eccezioni documentate sono
ArgumentNullExceptionper un percorso nullo,ArgumentExceptionquando un oggetto di opzioni non corrisponde al driver,GisExceptionquando una funzionalità non può essere letta dal file eIOExceptionper errori di I/O sottostanti.Posso convertire un batch di file TopoJSON tutti in una volta? Sì. Scorri l’elenco dei file e chiama
VectorLayer.Convertper ciascun file. Se parallelizzi il ciclo, assegna a ogni worker la propria istanza diVectorLayere delle opzioni anziché condividere un’unica istanza tra i thread.La conversione cambia il sistema di coordinate? Non per impostazione predefinita. Per riproiettare durante la conversione, impostare
ConversionOptions.DestinationSpatialReferenceSystemsul sistema di destinazione prima di chiamareConvert.
