TopoJSON es una codificación compacta de datos geográficos, y es común que cada característica en un archivo TopoJSON lleve un objeto de atributos en lugar de un conjunto plano de pares clave‑valor. Exportar esa estructura a CSV es donde normalmente surgen problemas: la mayoría de las herramientas o eliminan el objeto anidado o lo vuelcan de nuevo como una cadena JSON insertada en una sola celda. Esta guía muestra cómo convertir TopoJSON a CSV en C# usando Aspose.GIS, manteniendo cada atributo accesible como su propia columna y, opcionalmente, escribiendo la geometría junto a ella como Well‑Known Text.
El beneficio es que un conjunto de datos GIS jerárquico se convierte en una tabla plana que SQL Server, Power BI, pandas o una hoja de cálculo simple pueden consumir directamente, sin una capa de análisis JSON personalizada en su aplicación.
Por qué convertir TopoJSON a CSV usando Aspose.GIS
Considere una característica TopoJSON cuyas propiedades se ven así:
{
"name": "North District",
"prop1": { "this": "that" }
}
Un escritor CSV ingenuo tiene tres malas opciones: eliminar prop1, serializarlo como {"this":"that"} en una sola celda, o fallar. Las tres empujan el problema aguas abajo, donde alguien tiene que volver a analizar JSON de una columna de texto antes de poder filtrar o unir sobre ella.
Aspose.GIS adopta un enfoque diferente. Cuando el controlador TopoJSON lee el archivo, proyecta el objeto anidado en el esquema de la capa como un atributo plano llamado según su ruta, uniendo el padre y el hijo con un guion bajo. La característica anterior se expone como dos columnas ordinarias:
| Columna | Valor |
|---|---|
name | Distrito Norte |
prop1_this | eso |
Como el aplanamiento ocurre en tiempo de lectura, el paso de conversión no necesita ningún manejo especial. Lo que la capa expone es lo que se escribe, por lo que prop1_this aparece en el CSV como una columna de primera clase que puedes ordenar, filtrar y unir.
Requisitos previos para la conversión de TopoJSON a CSV
- .NET 6.0 o posterior, o .NET Framework 4.6.2 o posterior
- Aspose.GIS for .NET, instalado desde NuGet
- Un archivo TopoJSON que contiene al menos un objeto de atributo anidado
Instale el paquete con la CLI de .NET:
dotnet add package Aspose.GIS
O desde la Consola del Administrador de paquetes:
Install-Package Aspose.GIS
Un detalle de nomenclatura confunde a la gente: el paquete NuGet y el ensamblado se llaman Aspose.GIS, pero el espacio de nombres raíz es Aspose.Gis con una is en minúsculas. Las opciones del controlador CSV se encuentran en Aspose.Gis.Formats.Csv.
using Aspose.Gis;
using Aspose.Gis.Formats.Csv;
Los detalles del producto están en la página del producto Aspose.GIS for .NET, con la lista completa de tipos en la referencia de API.
Inspeccionar el esquema aplanado antes de convertir
Lo que lograrás: Abre la capa TopoJSON y muestra sus nombres de atributos para que sepas exactamente qué columnas contendrá el CSV.
Este paso vale la pena hacerlo una vez con un archivo representativo. Te indica los nombres reales de las columnas generados al aplanar, lo cual es mucho más fiable que adivinarlos a partir del JSON sin procesar.
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})");
}
}
Para la característica de ejemplo mostrada anteriormente, esto imprime name (String) y prop1_this (String). El objeto anidado nunca aparece como un atributo por sí mismo, lo cual es exactamente lo que deseas.
Convertir TopoJSON a CSV mientras se preservan los atributos anidados
Lo que lograrás: Cargar un archivo TopoJSON, escribir cada atributo aplanado en un archivo CSV y leer el resultado de nuevo para confirmar que la columna se ha transferido.
Proceso paso a paso
- Defina la ruta del TopoJSON de origen y la ruta del CSV de destino.
- Abra el origen con
VectorLayer.Openy confirme que el atributo aplanado existe. - Llame a la sobrecarga estática
VectorLayer.Convertcon los controladores de origen y destino. - Vuelva a abrir el CSV con
Drivers.Csvy verifique el recuento de columnas y los valores.
El siguiente ejemplo convierte un archivo TopoJSON a CSV, aplanando las propiedades anidadas en el proceso.
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}");
}
}
}
Explicación
VectorLayer.Open(string, FileDriver)abre el archivo en modo solo lectura.Drivers.TopoJsondevuelve el controlador para el formato TopoJSON.FeatureAttributeCollection.Contains(string)es la forma más económica de comprobar una columna por nombre.IndexOfte da su posición si la necesitas.VectorLayer.Convert(string, FileDriver, string, FileDriver)es un ayudante estático que transmite la fuente al formato de destino en una sola llamada. También hay una sobrecarga que aceptaConversionOptions, utilizada en la siguiente sección.Feature.GetValue<T>(string)lee un valor de atributo tipado. UsaGetValueOrDefault<T>(string)cuando una columna puede estar ausente o ser nula, ya queGetValue<T>asume que el valor está presente.- La comprobación final es la que sorprende a la gente. Un archivo CSV no tiene columna de geometría a menos que la crees, por lo que cada entidad vuelve con una geometría vacía. Ese es el comportamiento predeterminado, no un error de conversión, y la siguiente sección lo corrige.
Envolver ambas capas en bloques using es importante aquí: VectorLayer implementa IDisposable, y no se garantiza que el archivo de destino se vacíe y cierre hasta que se libere.
Incluir geometría como WKT usando CsvOptions
Lo que lograrás: Produce un CSV que contenga tanto los atributos aplanados y una columna que mantenga la geometría de cada entidad como Well-Known Text.
Proceso paso a paso
- Crea una instancia de
CsvOptionsy estableceColumnWktcon el nombre de columna que elijas. - Asigna la instancia a
ConversionOptions.DestinationDriverOptions. - Llama a la sobrecarga
VectorLayer.Convertque acepta opciones de conversión. - Vuelve a abrir el CSV con el mismo
CsvOptionspara que el controlador sepa qué columna analizar como geometría.
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}");
}
}
}
}
Explicación
CsvOptions.ColumnWktnombra la columna que contiene la geometría de cada entidad en forma WKT. Su valor predeterminado esnull, y dejarlo nulo o vacío es precisamente la razón por la que el ejemplo anterior no generó geometría.ConversionOptions.DestinationDriverOptionsestá tipado comoDriverOptions, la clase base para el objeto de configuración de cada controlador. Pasar unCsvOptionscuando el controlador de destino esDrivers.Csves lo que hace que la configuración tenga efecto; pasar opciones del tipo incorrecto para un controlador genera unaArgumentException.- La misma instancia de
CsvOptionsse reutiliza en el lado de lectura. Sin ella, el controlador CSV no tiene razón para tratarGeometryWktcomo algo distinto a otra columna de tipo cadena. IGeometry.AsText()devuelve la representación ISO WKT, por lo que la salida impresa coincide con lo que se escribió en el archivo.
La simetría es el punto: las columnas de atributos se comportan idénticamente, ya sea que la geometría esté incluida o no, por lo que puedes activar y desactivar la columna WKT sin tocar el resto de tu pipeline.
Reproyectar durante la conversión
Si el sistema consumidor espera un sistema de coordenadas específico, solicítelo como parte de la conversión en lugar de procesar el CSV después. ConversionOptions lleva una referencia espacial junto con las opciones del controlador:
var conversionOptions = new ConversionOptions
{
DestinationDriverOptions = new CsvOptions { ColumnWkt = "GeometryWkt" },
DestinationSpatialReferenceSystem = SpatialReferenceSystem.Wgs84
};
VectorLayer.Convert(sourcePath, Drivers.TopoJson, destinationPath, Drivers.Csv, conversionOptions);
No todos los controladores de destino admiten todos los sistemas de referencia espacial. Llame a Drivers.Csv.SupportsSpatialReferenceSystem(...) primero si el sistema de destino es configurable en tiempo de ejecución y recurra a un objeto de opciones nulo cuando no sea compatible.
Convertir por lotes una carpeta de archivos TopoJSON
La API es idéntica para un archivo y para mil. La única regla que vale la pena recordar al paralelizar es que cada trabajador necesita sus propios objetos de capa y de opciones.
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}");
}
});
}
Capturar GisException por archivo en lugar de alrededor de todo el bucle significa que un archivo TopoJSON malformado registra una advertencia en lugar de abortar el lote.
Obtén una licencia gratuita
Aspose.GIS se ejecuta en modo de evaluación hasta que se aplique una licencia. Solicite una licencia temporal gratuita en la página de licencia temporal de Aspose y aplíquela una vez al iniciar la aplicación, antes de cualquier otra llamada a Aspose.GIS:
var license = new Aspose.Gis.License();
license.SetLicense("Aspose.GIS.NET.lic");
Recursos adicionales gratuitos
Conclusión
Convertir TopoJSON con propiedades anidadas a CSV en .NET se reduce a un comportamiento útil: Aspose.GIS aplana los objetos de atributos anidados en columnas con nombre como prop1_this mientras se lee la capa, por lo que VectorLayer.Convert no necesita lógica personalizada para preservarlos. Añada CsvOptions.ColumnWkt cuando el sistema downstream necesite geometría, añada DestinationSpatialReferenceSystem cuando requiera una proyección específica, y repita la misma llamada en un bucle cuando necesite procesar una carpeta. El resultado es una tabla plana, lista para análisis, producida con unas pocas líneas de C#, sin una capa de análisis JSON propia que mantener.
FAQs
¿Puede Aspose.GIS aplanar objetos JSON anidados al convertir a CSV? Sí. El controlador TopoJSON expone un objeto de atributo anidado como columnas separadas cuando se abre la capa, uniendo los nombres de padre e hijo con un guion bajo, de modo que el aplanado ya se realiza antes de que se ejecute la conversión.
¿Necesito escribir código personalizado para manejar propiedades anidadas? No.
VectorLayer.Convertescribe cualquier columna que exponga la capa de origen, por lo que las propiedades anidadas no requieren código de análisis adicional por tu parte.¿Cómo puedo incluir la geometría en la salida CSV? Cree una instancia de
CsvOptions, establezca su propiedadColumnWktal nombre de columna que desea, asígnela aConversionOptions.DestinationDriverOptionsy pásela aVectorLayer.Convert.¿Por qué la geometría está vacía cuando vuelvo a leer mi CSV? Un CSV no tiene una columna de geometría a menos que la solicites. Establece
ColumnWkten elCsvOptionsque pasas tanto al escribir como al leer, de lo contrario el controlador no tiene ninguna columna desde la cual construir una geometría.¿Qué excepciones debo manejar durante la conversión? Las documentadas son
ArgumentNullExceptionpara una ruta nula,ArgumentExceptioncuando un objeto de opciones no coincide con el controlador,GisExceptioncuando una característica no se puede leer del archivo, yIOExceptionpara fallas subyacentes de E/S.¿Puedo convertir un lote de archivos TopoJSON de una vez? Sí. Recorra la lista de archivos y llame a
VectorLayer.Convertpara cada archivo. Si paraleliza el bucle, dé a cada trabajador su propia instancia deVectorLayery de opciones en lugar de compartir una entre hilos.¿Cambia la conversión el sistema de coordenadas? No, por defecto. Para reproyectar durante la conversión, establezca
ConversionOptions.DestinationSpatialReferenceSystemal sistema de destino antes de llamar aConvert.
