كيفية العمل مع العقد في .NET

كيفية العمل مع العقد في .NET

هذا الدليل يوضح كيفية استعراض، استعلام، وتعديل شجرة العقد في مستند Word مباشرةً في Aspose.Words FOSS لـ .NET, باستخدام Node and CompositeNode فئات القاعدة التي Document, Section, Paragraph, Table, وجميع عناصر المستند الأخرى مبنية عليها. يغطي تحديد نطاق البحث بواسطة NodeType, إضافة وإزالة العقد برمجيًا، الاستجابة للتغييرات الهيكلية، واستخدام DocumentVisitor للانتقال الموجه حسب النوع.

دليل خطوة بخطوة

الخطوة 1: تثبيت الحزمة

Aspose.Words FOSS for .NET لم ينشر بعد حزمة NuGet – قم ببناء المكتبة من المصدر بدلاً من ذلك. استنساخ https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git، ثم بناء Aspose.Words.sln في وضع الإصدار باستخدام مجموعة تطوير .NET SDK وربط تجميع Aspose.Words الناتج من مشروعك. تستهدف المكتبة .NET Standard 2.0، لذا فهي تعمل على .NET Framework 4.6.2+ و.NET 6/8/10.


الخطوة 2: استيراد الفئات المطلوبة

أضف توجيه using Aspose.Words; – Node، CompositeNode، NodeType، NodeCollection، NodeList، INodeChangingCallback، وDocumentVisitor جميعها موجودة في مساحة الأسماء Aspose.Words إلى جانب Document.


الخطوة 3: فهم العقدة وفئة القاعدة CompositeNode

كل كائن في شجرة المستند يشتق من الفئة المجردة Node، التي تُظهر NodeType (تحديد نوع العقدة)، ParentNode (الـ CompositeNode المحيط)، Document (المستند المالِك)، و PreviousSibling / NextSibling للتنقل عبر العقد على نفس المستوى. تحقق من Node.IsComposite لمعرفة ما إذا كانت العقدة المعطاة يمكنها احتواء أطفال قبل تحويلها. CompositeNode يمد Node لعناصر الحاوية — FirstChild، LastChild، و Count تصف أطفالها المباشرين، و HasChildNodes يُبلغ عما إذا كان هناك أي منها.


الخطوة 4: استعلام الأطفال حسب النوع

استدعِ CompositeNode.GetChildNodes(nodeType, isDeep) لاسترجاع كل طفل من NodeType معين، مع تمرير isDeep: true للبحث في الشجرة الفرعية بأكملها بدلاً من الأطفال المباشرين فقط، أو NodeType.Any لمطابقة كل نوع عقدة بغض النظر عن النوع. CompositeNode.GetChild(nodeType, index, isDeep) يسترجع طفلاً واحدًا متطابقًا بحسب الفهرس. لأنواع العقد الهيكلية (Document، Section، Body، Paragraph، Table، Row، Cell)، وأنواع المحتوى المتضمن (Run، Shape، Comment)، وأنواع آلية الحقول (FieldStart، FieldSeparator، FieldEnd، التي تحدد حدود حقل Word ونص التبديل في تدفق التشغيل)، مرّر قيمة NodeType المحددة التي تحدد ما تبحث عنه.


الخطوة 5: تنفيذ استعلامات XPath عبر شجرة فرعية

CompositeNode يطبق أيضًا SelectNodes(xpath) و SelectSingleNode(xpath) لاستعلامات مبنية على XPath عبر الشجرة الفرعية، ويعيد المطابقات كـ NodeList (أو Node واحد). CompositeNode.GetEnumerator() يدعم foreach عادي على الأطفال المباشرين للعقدة عندما يكون استعلام XPath أكثر مما يحتاجه المهمة.


الخطوة 6: إضافة، نقل، وإزالة العقد

لتعديل الشجرة، استدعِ 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 خاطئة isDeep تم تركه false (أو يُحذف حيث يكون التجاوز افتراضيًا ضحلًا). مرّر isDeep: true to GetChildNodes() للبحث في الشجرة الفرعية بأكملها بدلاً من الأطفال المباشرين.

تعديل مجموعة أثناء التكرار عليها يسبب حدوث خطأ تمت إضافة أو إزالة العقد داخل foreach فوق NodeCollection أو نتيجة GetChildNodes. استدع ToArray() أولاً لتجسيد العقد لتعديلها، ثم التكرار على تلك المصفوفة مع تعديل الشجرة.

فئة فرعية DocumentVisitor لا يتم استدعاؤها لبعض المحتوى تم استدعاء الزائر عبر Accept() على عقدة لا تحتوي فعليًا على المحتوى المستهدف، أو المقابل Visit* الطريقة لم تُغطى. استدع Accept() على سلف يحتوي على المحتوى، وتجاوز كل Visit*Start / Visit*End زوج ذو صلة بأنواع العقد التي يتم معالجتها.

INodeChangingCallback لا يتم إخطاره بتغيير الدالة الراجعة (callback) تُبلغ فقط عن التغييرات على الـ Document التي تم التسجيل ضدها. تأكد من أن الدالة الراجعة مرفقة بالـ 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 المدمج في تدفق التشغيل: FieldStart وFieldEnd يحددان الحقل، وFieldSeparator يفصل كود الحقل عن نتيجته المعروضة حاليًا.

كيف أقوم بمعالجة كل فقرة، وجدول، وrun في مستند؟

قم بإنشاء فئة فرعية من DocumentVisitor، وتجاوز طرق Visit*Start / Visit*End لأنواع العقد المطلوبة، ثم استدعِ Accept(visitor) على Document (أو أي جذر شجرة فرعية) لتشغيله.

انظر أيضاً

 العربية