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:

ColumnaValor
nameDistrito Norte
prop1_thiseso

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

  1. Defina la ruta del TopoJSON de origen y la ruta del CSV de destino.
  2. Abra el origen con VectorLayer.Open y confirme que el atributo aplanado existe.
  3. Llame a la sobrecarga estática VectorLayer.Convert con los controladores de origen y destino.
  4. Vuelva a abrir el CSV con Drivers.Csv y 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.TopoJson devuelve el controlador para el formato TopoJSON.
  • FeatureAttributeCollection.Contains(string) es la forma más económica de comprobar una columna por nombre. IndexOf te 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 acepta ConversionOptions, utilizada en la siguiente sección.
  • Feature.GetValue<T>(string) lee un valor de atributo tipado. Usa GetValueOrDefault<T>(string) cuando una columna puede estar ausente o ser nula, ya que GetValue<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

  1. Crea una instancia de CsvOptions y establece ColumnWkt con el nombre de columna que elijas.
  2. Asigna la instancia a ConversionOptions.DestinationDriverOptions.
  3. Llama a la sobrecarga VectorLayer.Convert que acepta opciones de conversión.
  4. Vuelve a abrir el CSV con el mismo CsvOptions para 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.ColumnWkt nombra la columna que contiene la geometría de cada entidad en forma WKT. Su valor predeterminado es null, y dejarlo nulo o vacío es precisamente la razón por la que el ejemplo anterior no generó geometría.
  • ConversionOptions.DestinationDriverOptions está tipado como DriverOptions, la clase base para el objeto de configuración de cada controlador. Pasar un CsvOptions cuando el controlador de destino es Drivers.Csv es lo que hace que la configuración tenga efecto; pasar opciones del tipo incorrecto para un controlador genera una ArgumentException.
  • La misma instancia de CsvOptions se reutiliza en el lado de lectura. Sin ella, el controlador CSV no tiene razón para tratar GeometryWkt como 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

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

  2. ¿Necesito escribir código personalizado para manejar propiedades anidadas? No. VectorLayer.Convert escribe 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.

  3. ¿Cómo puedo incluir la geometría en la salida CSV? Cree una instancia de CsvOptions, establezca su propiedad ColumnWkt al nombre de columna que desea, asígnela a ConversionOptions.DestinationDriverOptions y pásela a VectorLayer.Convert.

  4. ¿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 ColumnWkt en el CsvOptions que pasas tanto al escribir como al leer, de lo contrario el controlador no tiene ninguna columna desde la cual construir una geometría.

  5. ¿Qué excepciones debo manejar durante la conversión? Las documentadas son ArgumentNullException para una ruta nula, ArgumentException cuando un objeto de opciones no coincide con el controlador, GisException cuando una característica no se puede leer del archivo, y IOException para fallas subyacentes de E/S.

  6. ¿Puedo convertir un lote de archivos TopoJSON de una vez? Sí. Recorra la lista de archivos y llame a VectorLayer.Convert para cada archivo. Si paraleliza el bucle, dé a cada trabajador su propia instancia de VectorLayer y de opciones en lugar de compartir una entre hilos.

  7. ¿Cambia la conversión el sistema de coordenadas? No, por defecto. Para reproyectar durante la conversión, establezca ConversionOptions.DestinationSpatialReferenceSystem al sistema de destino antes de llamar a Convert.

Leer más