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 الملف، يقوم بإسقاط الكائن المتداخل في مخطط الطبقة كخاصية مسطحة تُسمى بناءً على مساره، مع ربط الأصل والطفل بشرطة سفلية. الميزة أعلاه تُعرض كعمودين عاديين:

العمودالقيمة
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) هي أداة مساعدة ثابتة تقوم ببث المصدر إلى تنسيق الوجهة في مكالمة واحدة. هناك أيضًا نسخة متجاوزة تأخذ ConversionOptions، تُستخدم في القسم التالي.
  • Feature.GetValue<T>(string) يقرأ قيمة سمة ذات نوع محدد. استخدم 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(...) أولاً إذا كان النظام المستهدف قابلًا للتكوين أثناء التشغيل، والرجوع إلى كائن خيارات فارغ عندما لا يكون مدعومًا.

تحويل دفعة لمجلد من ملفات 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 خاصة بك.

FAQs

  1. هل يمكن لـ Aspose.GIS تسطيح كائنات JSON المتداخلة عند التحويل إلى CSV؟ نعم. يُظهر برنامج تشغيل TopoJSON كائن السمة المتداخلة كأعمدة منفصلة عند فتح الطبقة، حيث يتم ربط أسماء الأصل والطفل بشرطة سفلية، وبالتالي يتم تنفيذ التسطيح بالفعل قبل بدء عملية التحويل.

  2. هل أحتاج إلى كتابة كود مخصص لمعالجة الخصائص المتداخلة؟ لا. VectorLayer.Convert يكتب أي أعمدة تعرضها الطبقة المصدر، لذلك لا تحتاج الخصائص المتداخلة إلى أي كود تحليل إضافي من جانبك.

  3. كيف يمكنني تضمين الهندسة في مخرجات CSV؟ أنشئ مثيلاً من CsvOptions، واضبط خاصية ColumnWkt إلى اسم العمود الذي تريده، ثم عينه إلى ConversionOptions.DestinationDriverOptions، ومرره إلى VectorLayer.Convert.

  4. لماذا تكون الهندسة فارغة عندما أقوم بقراءة ملف CSV مرة أخرى؟ ملف CSV لا يحتوي على عمود هندسة ما لم تطلب ذلك. قم بتعيين ColumnWkt على CsvOptions التي تمررها عند الكتابة والقراءة، وإلا لن يكون لدى السائق أي عمود يمكنه بناء الهندسة منه.

  5. ما الاستثناءات التي يجب عليّ التعامل معها أثناء التحويل؟ المستندة هي ArgumentNullException لمسار فارغ، ArgumentException عندما لا يتطابق كائن الخيارات مع السائق، GisException عندما لا يمكن قراءة ميزة من الملف، و IOException لأخطاء الإدخال/الإخراج الأساسية.

  6. هل يمكنني تحويل مجموعة من ملفات TopoJSON مرة واحدة؟ نعم. قم بالتكرار عبر قائمة الملفات واستدعِ VectorLayer.Convert لكل ملف. إذا قمت بتوازي الحلقة، أعطِ كل عامل مثيلًا خاصًا به من VectorLayer ونسخ الخيارات بدلاً من مشاركة واحدة عبر الخيوط.

  7. هل يغيّر التحويل نظام الإحداثيات؟ ليس بشكل افتراضي. لإعادة الإسقاط أثناء التحويل، قم بتعيين ConversionOptions.DestinationSpatialReferenceSystem إلى النظام المستهدف قبل استدعاء Convert.

اقرأ المزيد