TopoJSON یک رمزگذاری فشرده از داده‌های جغرافیایی است و معمولاً هر ویژگی در یک فایل TopoJSON یک شیء ویژگی به جای مجموعه‌ای مسطح از جفت‌های کلید‑مقدار حمل می‌کند. استخراج آن ساختار به CSV جایی است که معمولاً مشکلات پیش می‌آید: بیشتر ابزارها یا شیء تو در تو را حذف می‌کنند یا آن را به صورت رشته JSON در یک سلول واحد می‌اندازند. این راهنما نحوه تبدیل TopoJSON به CSV در C# را با استفاده از Aspose.GIS نشان می‌دهد، به‌طوری که هر ویژگی به‌صورت یک ستون قابل دسترسی باشد و به‌صورت اختیاری هندسه را به‌عنوان Well‑Known Text در کنار آن بنویسد.

نتیجه این است که یک مجموعه‌داده GIS سلسله‌مراتبی به یک جدول صاف تبدیل می‌شود که SQL Server، Power BI، pandas یا یک صفحه‌گسترده ساده می‌تواند به‌صورت مستقیم آن را مصرف کند، بدون هیچ لایهٔ سفارشی تجزیهٔ JSON در برنامهٔ شما.

چرا تبدیل TopoJSON به CSV با استفاده از Aspose.GIS

یک ویژگی TopoJSON را در نظر بگیرید که خصوصیات آن به این شکل است:

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

یک نویسندهٔ ساده CSV سه گزینهٔ بد دارد: حذف prop1، سریال‌سازی آن به صورت {"this":"that"} در یک سلول، یا شکست. هر سه این گزینه‌ها مشکل را به سمت پایین جریان می‌فرستند، جایی که کسی باید JSON را از یک ستون متنی دوباره تجزیه کند تا بتواند بر روی آن فیلتر یا جوین انجام دهد.

Aspose.GIS یک رویکرد متفاوت دارد. وقتی درایور TopoJSON فایل را می‌خواند، شیء تو در تو را به‌صورت یک ویژگی مسطح (flat attribute) که نام آن بر اساس مسیر آن است، به طرح‌واره لایه پروژه می‌کند و والد و فرزند را با یک underscore به هم می‌پیوندد. ویژگی فوق به‌عنوان دو ستون عادی نمایش داده می‌شود:

ستونمقدار
nameمنطقه شمالی
prop1_thisآن

از آنجا که صاف‌سازی در زمان خواندن انجام می‌شود، مرحله تبدیل نیازی به هیچ‌گونه پردازش خاصی ندارد. هر چیزی که لایه افشا می‌کند همان چیزی است که نوشته می‌شود، بنابراین prop1_this به عنوان یک ستون اصلی در CSV قرار می‌گیرد که می‌توانید آن را مرتب کنید، فیلتر کنید و به آن بپیوندید.

پیش‌نیازهای تبدیل TopoJSON به CSV

  • .NET 6.0 یا بالاتر، یا .NET Framework 4.6.2 یا بالاتر
  • Aspose.GIS for .NET، نصب شده از NuGet
  • یک فایل TopoJSON که حداقل یک شیء ویژگی تو در تو را شامل می‌شود

پکیج را با .NET CLI نصب کنید:

dotnet add package Aspose.GIS

یا از کنسول مدیر بسته:

Install-Package Aspose.GIS

یک جزئیات نام‌گذاری مردم را گیج می‌کند: بسته NuGet و اسمبلی با نام Aspose.GIS هستند، اما فضای نام ریشه Aspose.Gis با حروف کوچک is است. گزینه‌های درایور CSV در Aspose.Gis.Formats.Csv قرار دارند.

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

جزئیات محصول در صفحهٔ محصول Aspose.GIS for .NET موجود است و فهرست کامل انواع در مرجع API قرار دارد.

بررسی طرح‌وارهٔ صاف‌شده قبل از تبدیل

چه کاری انجام خواهید داد: لایه TopoJSON را باز کنید و نام‌های ویژگی آن را چاپ کنید تا دقیقاً بدانید که ستون‌های CSV چه خواهند بود.

این گام یک بار در مقابل یک فایل نماینده ارزش انجام دارد. این به شما نام‌های واقعی ستون‌ها را که توسط صاف‌سازی تولید می‌شوند می‌گوید، که بسیار قابل اعتمادتر از حدس زدن آن‌ها از JSON خام است.

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

برای ویژگی نمونه‌ای که قبلاً نشان داده شد، این مقدار name (String) و prop1_this (String) را چاپ می‌کند. شیء تو در تو هرگز به عنوان یک ویژگی به‌صورت مستقل ظاهر نمی‌شود، که دقیقاً همان چیزی است که می‌خواهید.

تبدیل TopoJSON به CSV در حالی که ویژگی‌های تو در تو حفظ می‌شوند

چه کاری انجام خواهید داد: یک فایل TopoJSON بارگذاری کنید، هر ویژگی صاف‌شده را به یک فایل CSV بنویسید، و نتیجه را بخوانید تا تأیید کنید که ستون به درستی منتقل شده است.

فرآیند گام به گام

  1. مسیر TopoJSON منبع و مسیر CSV مقصد را تعریف کنید.
  2. منبع را با VectorLayer.Open باز کنید و تأیید کنید که ویژگی مسطح موجود است.
  3. متد استاتیک VectorLayer.Convert را با درایورهای منبع و مقصد فراخوانی کنید.
  4. CSV را با Drivers.Csv دوباره باز کنید و تعداد ستون‌ها و مقادیر را بررسی کنید.

مثال زیر یک فایل TopoJSON را به CSV تبدیل می‌کند و در طول مسیر ویژگی‌های تو در تو را صاف می‌نماید.

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

توضیح

  • VectorLayer.Open(string, FileDriver) فایل را به صورت فقط‑خواندنی باز می‌کند. Drivers.TopoJson درایور فرمت TopoJSON را برمی‌گرداند.
  • FeatureAttributeCollection.Contains(string) ارزان‌ترین راه برای بررسی وجود یک ستون بر اساس نام است. IndexOf موقعیت آن را در صورت نیاز به شما می‌دهد.
  • VectorLayer.Convert(string, FileDriver, string, FileDriver) یک کمک‌کنندهٔ ایستا است که منبع را در یک فراخوانی به فرمت مقصد جریان می‌دهد. همچنین یک overload وجود دارد که ConversionOptions را می‌گیرد و در بخش بعدی استفاده می‌شود.
  • Feature.GetValue<T>(string) مقدار ویژگی با نوع مشخص را می‌خواند. زمانی که ممکن است یک ستون موجود نباشد یا مقدار آن null باشد، از GetValueOrDefault<T>(string) استفاده کنید، زیرا GetValue<T> فرض می‌کند مقدار موجود است.
  • بررسی نهایی همان چیزی است که مردم را شگفت‌زده می‌کند. یک فایل CSV ستون هندسی ندارد مگر اینکه خودتان آن را ایجاد کنید، بنابراین هر ویژگی با یک هندسهٔ خالی برمی‌گردد. این رفتار پیش‌فرض است، نه یک خطای تبدیل، و بخش بعدی این موضوع را برطرف می‌کند.

در اینجا بسته‌بندی هر دو لایه در بلوک‌های using مهم است: VectorLayer پیاده‌سازی IDisposable را دارد و تا زمانی که تخلیه نشود، تضمین نمی‌شود که فایل مقصد پاک‌سازی و بسته شود.

گنجاندن هندسه به صورت WKT با استفاده از CsvOptions

چیزی که خواهید انجام داد: یک CSV تولید کنید که هم ویژگی‌های صاف‌شده را حمل می‌کند و یک ستون حاوی هندسه هر ویژگی به صورت Well-Known Text داشته باشد.

فرآیند گام به گام

  1. یک نمونه از CsvOptions ایجاد کنید و ColumnWkt را به نام ستونی که انتخاب کرده‌اید تنظیم کنید.
  2. آن را به ConversionOptions.DestinationDriverOptions اختصاص دهید.
  3. متد VectorLayer.Convert که گزینه‌های تبدیل را می‌پذیرد فراخوانی کنید.
  4. CSV را با همان CsvOptions دوباره باز کنید تا درایور بداند کدام ستون به عنوان هندسه تجزیه شود.
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}");
            }
        }
    }
}

توضیح

  • CsvOptions.ColumnWkt نام ستونی را که هندسه هر ویژگی را به صورت WKT نگه می‌دارد، تعیین می‌کند. پیش‌فرض آن null است و گذاشتن آن به صورت null یا خالی دقیقاً دلیل این است که مثال قبلی هیچ هندسه‌ای تولید نکرد.
  • ConversionOptions.DestinationDriverOptions به عنوان DriverOptions تعریف شده است، کلاس پایه برای شیء تنظیمات هر درایور. ارسال یک CsvOptions زمانی که درایور مقصد Drivers.Csv باشد، باعث فعال شدن تنظیم می‌شود؛ ارسال گزینه‌ها با نوع نادرست برای یک درایور باعث بروز ArgumentException می‌شود.
  • همان نمونه CsvOptions در سمت خواندن دوباره استفاده می‌شود. بدون آن، درایور CSV هیچ دلیلی برای در نظر گرفتن GeometryWkt به عنوان چیزی جز یک ستون رشته‌ای دیگر ندارد.
  • IGeometry.AsText() نمایهٔ ISO WKT را برمی‌گرداند، بنابراین خروجی چاپ‌شده با آنچه در فایل نوشته شده مطابقت دارد.

تقارن نکته اصلی است: ستون‌های ویژگی به‌طور یکسان رفتار می‌کنند، چه جغرافیا گنجانده شده باشد چه نباشد، بنابراین می‌توانید ستون WKT را روشن یا خاموش کنید بدون اینکه به بقیهٔ خط لوله‌تان دست بزنید.

بازپروژه‌سازی در حین تبدیل

اگر سیستم مصرف‌کننده انتظار یک سیستم مختصات خاص را داشته باشد، به‌جای پردازش پس از تبدیل CSV، آن را به‌عنوان بخشی از تبدیل درخواست کنید. ConversionOptions یک مرجع فضایی را همراه با گزینه‌های درایور حمل می‌کند:

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

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

هر درایور مقصد همه سیستم‌های مرجع فضایی را پشتیبانی نمی‌کند. ابتدا اگر سیستم هدف در زمان اجرا قابل پیکربندی باشد، Drivers.Csv.SupportsSpatialReferenceSystem(...) را فراخوانی کنید و اگر پشتیبانی نشد، به یک شیء گزینه‌های null بازگردید.

تبدیل دسته‌ای یک پوشه از فایل‌های TopoJSON

API برای یک فایل و برای هزار فایل یکسان است. تنها قانونی که هنگام موازی‌سازی باید به خاطر داشته باشید این است که هر کارگر به لایه و اشیاء گزینه‌های خود نیاز دارد.

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

گرفتن GisException برای هر فایل به‌جای دور تمام حلقه به این معنی است که یک فایل TopoJSON خراب، یک هشدار را ثبت می‌کند به‌جای اینکه پردازش دسته‌ای را متوقف کند.

دریافت یک لایسنس رایگان

Aspose.GIS تا زمانی که یک لایسنس اعمال شود، در حالت ارزیابی اجرا می‌شود. یک لایسنس موقت رایگان را از صفحه لایسنس موقت Aspose درخواست کنید و آن را یک‌بار در زمان راه‌اندازی برنامه، قبل از هر فراخوانی دیگر Aspose.GIS اعمال کنید:

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

منابع اضافی رایگان

نتیجه‌گیری

تبدیل TopoJSON با ویژگی‌های تو در تو به CSV در .NET به یک رفتار مفید بستگی دارد: Aspose.GIS ویژگی‌های تو در تو را به ستون‌های نام‌دار مانند prop1_this مسطح می‌کند در حالی که لایه خوانده می‌شود، بنابراین VectorLayer.Convert نیازی به منطق سفارشی برای حفظ آن‌ها ندارد. هنگام نیاز سیستم پایین‌دستی به هندسه، CsvOptions.ColumnWkt را اضافه کنید، هنگام نیاز به پروجکشن خاص DestinationSpatialReferenceSystem را اضافه کنید، و برای پردازش یک پوشه همان فراخوانی را حلقه بزنید. نتیجه یک جدول صاف و آماده برای تحلیل است که با چند خط C# تولید می‌شود و نیازی به لایه تجزیه JSON خودتان ندارید.

سوالات متداول

  1. آیا Aspose.GIS می‌تواند اشیاء JSON تو در تو را هنگام تبدیل به CSV صاف کند؟ بله. درایور TopoJSON یک شیء ویژگی تو در تو را به عنوان ستون‌های جداگانه نمایش می‌دهد هنگامی که لایه باز می‌شود، نام‌های والد و فرزند را با یک underscore ترکیب می‌کند، بنابراین صاف‌سازی قبلاً قبل از اجرای تبدیل انجام می‌شود.

  2. آیا نیاز به نوشتن کد سفارشی برای مدیریت ویژگی‌های تو در تو دارم؟ نه. VectorLayer.Convert هر ستونی را که لایه منبع در دسترس می‌گذارد می‌نویسد، بنابراین ویژگی‌های تو در تو نیازی به کد تجزیه اضافی از طرف شما ندارند.

  3. چگونه می‌توانم هندسه را در خروجی CSV گنجانده کنم؟ یک نمونه از CsvOptions ایجاد کنید، ویژگی ColumnWkt آن را به نام ستونی که می‌خواهید تنظیم کنید، آن را به ConversionOptions.DestinationDriverOptions اختصاص دهید، و آن را به VectorLayer.Convert پاس دهید.

  4. چرا هنگام خواندن CSV دوباره، هندسه خالی است؟ یک CSV ستون هندسه‌ای ندارد مگر اینکه شما یکی درخواست کنید. ColumnWkt را در CsvOptions که هم هنگام نوشتن و هم هنگام خواندن پاس می‌دهید تنظیم کنید، در غیر این صورت درایور ستونی برای ساختن هندسه ندارد.

  5. در طول تبدیل باید چه استثناهایی را مدیریت کنم؟ استثناهای مستند عبارتند از ArgumentNullException برای مسیر null، ArgumentException زمانی که شیء گزینه‌ها با درایور مطابقت ندارد، GisException زمانی که یک ویژگی را نمی‌توان از فایل خواند، و IOException برای خطاهای زیرساختی I/O.

  6. آیا می‌توانم یک دسته از فایل‌های TopoJSON را به‌صورت همزمان تبدیل کنم؟ بله. بر روی فهرست فایل‌ها حلقه بزنید و برای هر فایل VectorLayer.Convert را فراخوانی کنید. اگر حلقه را به صورت موازی اجرا کنید، به هر کارگر یک نمونهٔ جداگانه از VectorLayer و گزینه‌ها بدهید به جای اینکه یک نمونه را بین رشته‌ها به اشتراک بگذارید.

  7. آیا تبدیل سیستم مختصات را تغییر می‌دهد؟ به‌طور پیش‌فرض نه. برای بازپروژه‌سازی در حین تبدیل، ConversionOptions.DestinationSpatialReferenceSystem را قبل از فراخوانی Convert به سیستم هدف تنظیم کنید.

بیشتر بخوانید