نحوه کار با گرهها در .NET
این راهنما نشان میدهد چگونه میتوان بهصورت مستقیم در Aspose.Words FOSS برای .NET، با استفاده از Node and CompositeNode کلاسهای پایهای که Document, Section, Paragraph, Table، و تمام عناصر دیگر سند بر پایهٔ آن ساخته شدهاند. این راهنما محدودهٔ جستجو را بر اساس NodeType، افزودن و حذف گرهها بهصورت برنامهنویسی، واکنش به تغییرات ساختاری، و استفاده از DocumentVisitor برای پیمایش بر پایهٔ نوع.
راهنمای گامبهگام
گام ۱: نصب بسته
Aspose.Words FOSS برای .NET هنوز بستهٔ NuGet را منتشر نکرده است – بهجای آن کتابخانه را از منبع بسازید. https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git را کلون کنید، سپس Aspose.Words.sln را در پیکربندی Release با .NET SDK بسازید و اسمبلی Aspose.Words حاصل را در پروژهتان ارجاع دهید. این کتابخانه هدفگذاری شده برای .NET Standard 2.0 است، بنابراین بر روی .NET Framework 4.6.2+ و .NET 6/8/10 اجرا میشود.
گام ۲: وارد کردن کلاسهای مورد نیاز
یک دستور using Aspose.Words; اضافه کنید – Node، CompositeNode، NodeType، NodeCollection، NodeList، INodeChangingCallback و DocumentVisitor همگی در فضای نام Aspose.Words همراه با Document قرار دارند.
مرحله ۳: درک Node و کلاسهای پایه CompositeNode
هر شیءای در درخت سند از کلاس انتزاعی Node مشتق میشود که NodeType (شناسایی نوع گره) ، ParentNode ( CompositeNode احاطهکننده) ، Document (سند مالک) و PreviousSibling / NextSibling را برای حرکت بین گرهها در همان سطح ارائه میدهد. برای فهمیدن اینکه آیا گرهٔ دادهشده میتواند فرزند داشته باشد قبل از تبدیل آن، Node.IsComposite را بررسی کنید. CompositeNode کلاس Node را برای عناصر محفظهای گسترش میدهد — FirstChild، LastChild و Count فرزندان مستقیم آن را توصیف میکنند، و HasChildNodes گزارش میدهد آیا هیچکدام وجود دارند.
مرحله ۴: دریافت فرزندان بر اساس نوع
برای دریافت هر فرزند از یک NodeType مشخص، CompositeNode.GetChildNodes(nodeType, isDeep) را فراخوانی کنید؛ با عبور isDeep: true میتوانید کل زیردرخت را جستجو کنید نه فقط فرزندان مستقیم، یا با NodeType.Any میتوانید هر نوع گرهای را صرفنظر از دستهبندی مطابقت دهید. CompositeNode.GetChild(nodeType, index, isDeep) یک فرزند مطابق را بر اساس اندیس بازمیگرداند. برای انواع گرههای ساختاری (Document، Section، Body، Paragraph، Table، Row، Cell)، انواع محتوای درونخطی (Run، Shape، Comment)، و انواع مکانیزم فیلد (FieldStart، FieldSeparator، FieldEnd که مرزهای یک فیلد Word و متن سوئیچ در جریان run را نشان میدهند)، مقدار خاص NodeType را که آنچه میخواهید را شناسایی میکند، ارسال کنید.
مرحله ۵: اجرای پرسوجوهای XPath در سرتاسر یک زیردرخت
CompositeNode همچنین SelectNodes(xpath) و SelectSingleNode(xpath) را برای پرسوجوهای مبتنی بر XPath در سراسر زیردرخت پیادهسازی میکند، که نتایج را بهصورت NodeList (یا یک Node منفرد) برمیگرداند. CompositeNode.GetEnumerator() یک foreach ساده را بر روی فرزندان مستقیم یک گره پشتیبانی میکند وقتی که یک پرسوجوی XPath بیش از نیاز کار باشد.
مرحله ۶: افزودن، جابجایی و حذف گرهها
برای تغییر درخت، AppendChild(newChild) یا PrependChild(newChild) را فراخوانی کنید تا گرهای را در ابتدا یا انتهای فرزندان یک محفظه اضافه کنید، و InsertBefore(newChild, refChild) یا InsertAfter(newChild, refChild) را برای درج نسبی به یک فرزند موجود استفاده کنید. RemoveChild(oldChild) یک فرزند را حذف میکند، و RemoveAllChildren() تمام فرزندان را یکباره پاک میکند؛ CompositeNode.IndexOf(child) موقعیت یک فرزند را گزارش میدهد. در خود Node، Clone(isCloneChildren) گرهای را کپی میکند — بهصورت اختیاری شامل فرزندان آن — و Remove() گره را از والد آن جدا میکند.
مرحله 7: قبل از تغییر یک مجموعه زنده، گرهها را مادیسازی کنید
تغییر یک مجموعه در حالی که یک حلقه foreach بر روی آن در حال تکرار است – چه یک NodeCollection باشد یا نتیجهٔ GetChildNodes – خطا ایجاد میکند. ابتدا ToArray() را روی مجموعه صدا بزنید تا گرهها را به یک آرایه ثابت مادیسازی کنید، سپس بر روی آن آرایه تکرار کنید در حالی که Remove() را فراخوانی میکنید یا تغییرات دیگری در درخت اعمال مینمایید.
مرحله 8: اسکن یک زیر درخت به ترتیب سند
Node.NextPreOrder(rootNode) و PreviousPreOrder(rootNode) درخت را به ترتیب سند، محدود به یک گره ریشهٔ دادهشده، پیمایش میکنند – روشی رایج برای اسکن تمام زیردرخت گره به گره بدون نوشتن کد پیمایش بازگشتی است.
مرحله 9: پردازش هر نوع گره با DocumentVisitor
برای پردازش انواع مختلف گرهها به صورت ساختار یافته، کلاس انتزاعی DocumentVisitor را زیرکلاس کنید و متدهای Visit*Start / Visit*End را برای انواع گرهای که مهم هستند بازنویسی کنید – برای مثال VisitParagraphStart / VisitParagraphEnd، VisitSectionStart / VisitSectionEnd، VisitBodyStart / VisitBodyEnd – سپس Node.Accept(visitor) را بر روی ریشهٔ زیردرخت فراخوانی کنید تا اجرا شود. این الگوی استاندارد برای استخراج، تبدیل یا بازرسی یک سند بدون نوشتن پیمایش بازگشتی سفارشی برای هر مورد استفاده است.
مرحله 10: واکنش به تغییرات ساختاری ایجاد شده توسط کدهای دیگر
زمانی که کد نیاز به واکنش به درجها یا حذفهایی دارد که توسط کدهای دیگر – از جمله عملیاتهای داخلی – انجام شدهاند (نه فقط تغییرات مستقیم)، INodeChangingCallback را پیادهسازی کنید. متدهای NodeInserting(args)، NodeInserted(args)، NodeRemoving(args) و NodeRemoved(args) هر کدام یک NodeChangingArgs دریافت میکنند که توصیفکنندهٔ Node تحت تأثیر، والد قبلی و جدید آن، و NodeChangingAction (Insert یا Remove) رخ داده است.
مشکلات رایج و راهحلها
تبدیل یک گره به CompositeNode خطای تبدیل نامعتبر را ایجاد میکند گره یک نوع برگ است – برای مثال Run or FieldStart – که نمیتواند فرزندان داشته باشد. بررسی کنید Node.IsComposite اول، یا استفاده کنید NodeType برای تأیید اینکه گره یک نوع مخزن است قبل از تبدیل.
GetChildNodes فرزندان مستقیم را زمانی که isDeep برابر false است برمیگرداند isDeep مانده بود false (یا حذف شده جایی که بارگذاری بیش از حد به صورت سطحی پیشفرض میشود). پاس دهید isDeep: true to GetChildNodes() برای جستجوی کل زیرشاخه به جای فرزندان مستقیم.
تغییر یک مجموعه در حین تکرار بر روی آن باعث بروز خطا میشود گرهها داخل یک اضافه یا حذف شدند foreach بر روی یک NodeCollection یا نتیجهٔ GetChildNodes. فراخوانی ToArray() ابتدا گرههای مورد تغییر را بهوجود آورید، سپس بر روی آن آرایه تکرار کنید در حالی که درخت را تغییر میدهید.
یک زیرکلاس DocumentVisitor برای برخی محتوا فراخوانی نمیشود بازدیدکننده از طریق Accept() بر روی گرهای که در واقع محتوی هدف را شامل نمیشود، یا Visit* متد بازنویسی نشده بود. فراخوانی Accept() بر روی یک نیاکی که محتوا را شامل میشود، و هر Visit*Start / Visit*End جفت مربوط به انواع گرههای در حال پردازش.
INodeChangingCallback دربارهٔ تغییر اطلاع داده نمیشود Callback فقط تغییرات را در Document که در آن ثبت شده بود. تأیید کنید که callback به Document نمونه قبل از وقوع تغییر، نه پس از آن.
سوالات متداول
تفاوت بین Node و CompositeNode چیست؟
Node کلاس پایهای است که هر عنصر سند از آن ارث میبرد. CompositeNode Node را برای عناصری که میتوانند فرزند داشته باشند (مانند Body، Paragraph و Table) گسترش میدهد؛ عناصر برگ مانند Run مستقیماً از Node ارث میبرند و نمیتوانند فرزند داشته باشند.
چگونه میتوانم تمام نودهای یک نوع خاص را در یک سند پیدا کنم؟
متد CompositeNode.GetChildNodes(nodeType, isDeep) را بر روی نودی که ریشه جستجو است فراخوانی کنید – که اغلب خود Document است – و NodeType هدف و isDeep: true را پاس کنید تا کل زیردرخت را جستجو کنید، نه فقط فرزندان مستقیم.
چگونه میتوانم نودها را بهصورت ایمن هنگام تکرار حذف کنم؟
ابتدا نودهای مورد نظر برای حذف را در یک آرایه جمعآوری کنید – برای مثال با NodeCollection.ToArray() – سپس بر روی آن آرایه تکرار کنید و برای هر نود Remove() را فراخوانی کنید، بهجای اینکه در حین تکرار foreach مجموعه زنده را تغییر دهید.
نودهای FieldStart، FieldSeparator و FieldEnd چه هستند؟
آنها مقادیر NodeType هستند که مکانیزم یک فیلد Word را که در جریان اجرا (run stream) جاسازی شده نشان میدهند: FieldStart و FieldEnd فیلد را محدود میکنند، و FieldSeparator کد فیلد را از نتیجهی فعلی نمایشدادهشدهی آن جدا میکند.
چگونه میتوانم هر پاراگراف، جدول و run را در یک سند پردازش کنم؟
کلاس DocumentVisitor را زیرکلاس کنید، متدهای Visit*Start / Visit*End را برای انواع گرههای مورد نیاز بازنویسی کنید، سپس Accept(visitor) را بر روی Document (یا هر ریشه زیردرخت) فراخوانی کنید تا اجرا شود.