TopoJSON é uma codificação compacta de dados geográficos, e é comum que cada recurso em um arquivo TopoJSON carregue um objeto de atributos em vez de um conjunto plano de pares chave‑valor. Exportar essa estrutura para CSV é onde as coisas geralmente dão errado: a maioria das ferramentas ou descarta o objeto aninhado ou o despeja de volta como uma string JSON inserida em uma única célula. Este guia mostra como converter TopoJSON para CSV em C# usando Aspose.GIS, mantendo cada atributo endereçável como sua própria coluna e, opcionalmente, gravando a geometria ao lado como Well‑Known Text.

A vantagem é que um conjunto de dados GIS hierárquico se torna uma tabela plana que o SQL Server, o Power BI, o pandas ou uma planilha simples podem consumir diretamente, sem uma camada personalizada de análise JSON em sua aplicação.

Por que converter TopoJSON para CSV usando Aspose.GIS

Considere um recurso TopoJSON cujas propriedades se parecem com isto:

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

Um escritor CSV ingênuo tem três opções ruins: descartar prop1, serializá‑lo como {"this":"that"} em uma única célula ou falhar. Todas as três empurram o problema para baixo, onde alguém precisa reanalisar o JSON de uma coluna de texto antes de poder filtrar ou fazer join nele.

Aspose.GIS adota uma abordagem diferente. Quando o driver TopoJSON lê o arquivo, ele projeta o objeto aninhado no esquema da camada como um atributo plano nomeado de acordo com seu caminho, unindo pai e filho com um sublinhado. O recurso acima é exposto como duas colunas comuns:

ColunaValor
nameDistrito Norte
prop1_thisisso

Como o achatamento ocorre no momento da leitura, a etapa de conversão não precisa de nenhum tratamento especial. O que quer que a camada exponha é o que é gravado, então prop1_this aparece no CSV como uma coluna de primeira classe que você pode ordenar, filtrar e fazer junções.

Pré-requisitos da Conversão de TopoJSON para CSV

  • .NET 6.0 ou posterior, ou .NET Framework 4.6.2 ou posterior
  • Aspose.GIS for .NET, instalado a partir do NuGet
  • Um arquivo TopoJSON contendo pelo menos um objeto de atributo aninhado

Instale o pacote com o .NET CLI:

dotnet add package Aspose.GIS

Ou pelo Console do Gerenciador de Pacotes:

Install-Package Aspose.GIS

Um detalhe de nomenclatura pega as pessoas desprevenidas: o pacote NuGet e o assembly são chamados Aspose.GIS, mas o namespace raiz é Aspose.Gis com um is minúsculo. As opções do driver CSV estão em Aspose.Gis.Formats.Csv.

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

Os detalhes do produto estão na página do produto Aspose.GIS for .NET, com a lista completa de tipos na referência da API.

Inspecione o Esquema Achatado Antes de Converter

O que você vai realizar: Abra a camada TopoJSON e imprima os nomes dos atributos para saber exatamente quais colunas o CSV conterá.

Esta etapa vale a pena ser feita uma vez em um arquivo representativo. Ela informa os nomes reais das colunas gerados pelo achatamento, o que é muito mais confiável do que adivinhá‑los a partir do JSON bruto.

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 o recurso de exemplo mostrado anteriormente, isso imprime name (String) e prop1_this (String). O objeto aninhado nunca aparece como um atributo por si só, o que é exatamente o que você deseja.

Converter TopoJSON para CSV preservando atributos aninhados

O que você vai realizar: Carregue um arquivo TopoJSON, escreva cada atributo achatado em um arquivo CSV e leia o resultado de volta para confirmar que a coluna foi preservada.

Processo passo a passo

  1. Defina o caminho de origem do TopoJSON e o caminho de destino do CSV.
  2. Abra a origem com VectorLayer.Open e confirme que o atributo achatado existe.
  3. Chame a sobrecarga estática VectorLayer.Convert com os drivers de origem e destino.
  4. Reabra o CSV com Drivers.Csv e verifique a contagem de colunas e os valores.

O exemplo a seguir converte um arquivo TopoJSON para CSV, achatando propriedades aninhadas ao longo do caminho.

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

Explicação

  • VectorLayer.Open(string, FileDriver) abre o arquivo somente leitura. Drivers.TopoJson devolve o driver para o formato TopoJSON.
  • FeatureAttributeCollection.Contains(string) é a maneira mais econômica de testar a existência de uma coluna por nome. IndexOf fornece sua posição caso você precise.
  • VectorLayer.Convert(string, FileDriver, string, FileDriver) é um helper estático que transmite a origem para o formato de destino em uma única chamada. Também há uma sobrecarga que aceita ConversionOptions, usada na seção seguinte.
  • Feature.GetValue<T>(string) lê um valor de atributo tipado. Use GetValueOrDefault<T>(string) quando uma coluna pode estar ausente ou nula, já que GetValue<T> assume que o valor está presente.
  • A verificação final é a que surpreende as pessoas. Um arquivo CSV não possui coluna de geometria a menos que você crie uma, portanto cada feature retorna com geometria vazia. Esse é o comportamento padrão, não uma falha de conversão, e a seção seguinte corrige isso.

Envolver ambas as camadas em blocos using é importante aqui: VectorLayer implementa IDisposable e o arquivo de destino não tem garantia de ser descarregado e fechado até que seja descartado.

Incluir Geometria como WKT Usando CsvOptions

O que você realizará: Produza um CSV que contenha tanto os atributos achatados e uma coluna contendo a geometria de cada recurso como Well-Known Text.

Processo passo a passo

  1. Crie uma instância de CsvOptions e defina ColumnWkt para o nome da coluna escolhido.
  2. Atribua‑a a ConversionOptions.DestinationDriverOptions.
  3. Chame a sobrecarga VectorLayer.Convert que aceita opções de conversão.
  4. Reabra o CSV com o mesmo CsvOptions para que o driver saiba qual coluna analisar como 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}");
            }
        }
    }
}

Explicação

  • CsvOptions.ColumnWkt nomeia a coluna que contém a geometria de cada recurso em forma WKT. O padrão é null, e deixá‑la nula ou vazia é exatamente o motivo pelo qual o exemplo anterior não produziu geometria.
  • ConversionOptions.DestinationDriverOptions é tipado como DriverOptions, a classe base para o objeto de configurações de cada driver. Passar um CsvOptions onde o driver de destino é Drivers.Csv é o que faz a configuração ter efeito; passar opções do tipo errado para um driver gera uma ArgumentException.
  • A mesma instância de CsvOptions é reutilizada no lado de leitura. Sem ela, o driver CSV não tem razão para tratar GeometryWkt como algo diferente de outra coluna de string.
  • IGeometry.AsText() retorna a representação ISO WKT, portanto a saída impressa corresponde ao que foi escrito no arquivo.

A simetria é o ponto: as colunas de atributos se comportam de forma idêntica, independentemente de a geometria estar incluída ou não, de modo que você pode ativar e desativar a coluna WKT sem tocar no restante do seu pipeline.

Reprojetar durante a conversão

Se o sistema consumidor espera um sistema de coordenadas específico, solicite‑o como parte da conversão em vez de pós‑processar o CSV. ConversionOptions carrega uma referência espacial juntamente com as opções do driver:

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

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

Nem todo driver de destino suporta todos os sistemas de referência espacial. Chame Drivers.Csv.SupportsSpatialReferenceSystem(...) primeiro se o sistema de destino for configurável em tempo de execução e recorra a um objeto de opções nulo quando não for suportado.

Conversão em lote de uma pasta de arquivos TopoJSON

A API é idêntica para um arquivo e para mil. A única regra que vale a pena lembrar ao paralelizar é que cada worker precisa de seus próprios objetos de camada e de opções.

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 arquivo em vez de ao redor de todo o loop significa que um arquivo TopoJSON malformado registra um aviso em vez de abortar o lote.

Obtenha uma Licença Gratuita

O Aspose.GIS funciona em modo de avaliação até que uma licença seja aplicada. Solicite uma licença temporária gratuita na página de licença temporária da Aspose e aplique‑a uma vez na inicialização da aplicação, antes de qualquer outra chamada ao Aspose.GIS:

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

Recursos Adicionais Gratuitos

Conclusão

Converter TopoJSON com propriedades aninhadas para CSV em .NET se resume a um comportamento útil: Aspose.GIS achata objetos de atributos aninhados em colunas nomeadas como prop1_this enquanto a camada está sendo lida, portanto VectorLayer.Convert não precisa de lógica personalizada para preservá‑los. Adicione CsvOptions.ColumnWkt quando o sistema downstream precisar de geometria, adicione DestinationSpatialReferenceSystem quando precisar de uma projeção específica e repita a mesma chamada quando precisar processar uma pasta. O resultado é uma tabela plana, pronta para análise, produzida por algumas linhas de C#, sem a necessidade de manter uma camada de análise JSON própria.

FAQs

  1. O Aspose.GIS pode achatar objetos JSON aninhados ao converter para CSV? Sim. O driver TopoJSON expõe um objeto de atributo aninhado como colunas separadas quando a camada é aberta, unindo os nomes do pai e do filho com um sublinhado, de modo que o achatamento já é realizado antes da execução da conversão.

  2. Preciso escrever código personalizado para lidar com propriedades aninhadas? Não. VectorLayer.Convert grava quaisquer colunas que a camada de origem expõe, portanto, propriedades aninhadas não precisam de código de análise extra da sua parte.

  3. Como posso incluir geometria na saída CSV? Crie uma instância de CsvOptions, defina sua propriedade ColumnWkt para o nome da coluna que deseja, atribua‑a a ConversionOptions.DestinationDriverOptions e passe isso para VectorLayer.Convert.

  4. Por que a geometria está vazia quando leio meu CSV de volta? Um CSV não tem coluna de geometria a menos que você solicite uma. Defina ColumnWkt nas CsvOptions que você passa tanto ao gravar quanto ao ler, caso contrário o driver não tem coluna da qual construir uma geometria.

  5. Quais exceções devo tratar durante a conversão? As documentadas são ArgumentNullException para um caminho nulo, ArgumentException quando um objeto de opções não corresponde ao driver, GisException quando um recurso não pode ser lido do arquivo e IOException para falhas subjacentes de E/S.

  6. Posso converter um lote de arquivos TopoJSON de uma vez? Sim. Percorra a lista de arquivos e chame VectorLayer.Convert para cada arquivo. Se você paralelizar o loop, dê a cada trabalhador sua própria instância de VectorLayer e de opções, em vez de compartilhar uma entre as threads.

  7. A conversão altera o sistema de coordenadas? Não por padrão. Para reprojetar durante a conversão, defina ConversionOptions.DestinationSpatialReferenceSystem para o sistema de destino antes de chamar Convert.

Leia Mais