วิธีทำงานกับโหนดใน .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 ในโหมด Release ด้วย .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: ทำความเข้าใจ Node และคลาสฐาน 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 ยัง implements 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) ที่เกิดขึ้น.

ปัญหาทั่วไปและวิธีแก้

การแคสท์ Node ไปยัง CompositeNode จะทำให้เกิดข้อผิดพลาดการแคสท์ที่ไม่ถูกต้อง โหนดเป็นประเภท leaf – ตัวอย่างเช่น Run or FieldStart – ที่ไม่สามารถบรรจุโหนดลูกได้ ตรวจสอบ Node.IsComposite ก่อน, หรือใช้ NodeType เพื่อยืนยันว่าโหนดเป็นประเภท container ก่อนทำการแคสท์.

GetChildNodes คืนค่าโหนดลูกโดยตรงเมื่อ isDeep เป็น false isDeep ถูกทิ้งไว้ false (หรือละเว้นเมื่อ overload มีค่าเริ่มต้นเป็น shallow) ส่ง isDeep: true to GetChildNodes() เพื่อค้นหาต้นไม้ย่อยทั้งหมดแทนโหนดลูกโดยตรง.

การแก้ไขคอลเลกชันขณะวนซ้ำผ่านมันทำให้เกิดข้อผิดพลาด โหนดถูกเพิ่มหรือถูกลบภายใน a foreach เหนือ a NodeCollection หรือผลลัพธ์ของ GetChildNodes. เรียก ToArray() ก่อนเพื่อทำให้โหนดที่ต้องการแก้ไขเป็นรูปธรรม แล้วจึงวนซ้ำผ่านอาร์เรย์นั้นขณะทำการเปลี่ยนแปลงต้นไม้.

คลาสย่อย DocumentVisitor ไม่ถูกเรียกสำหรับเนื้อหาบางส่วน ผู้เยี่ยมชมถูกเรียกใช้ผ่าน Accept() บนโหนดที่จริง ๆ แล้วไม่ได้มีเนื้อหาเป้าหมายอยู่, หรือเมธอดที่สอดคล้องกัน Visit* เมธอดไม่ได้ถูกโอเวอร์ไรด์. เรียก Accept() บนโหนดบรรพบุรุษที่มีเนื้อหาอยู่, และโอเวอร์ไรด์ทุก Visit*Start / Visit*End คู่ที่เกี่ยวข้องกับประเภทของโหนดที่กำลังประมวลผล.

INodeChangingCallback ไม่ได้รับการแจ้งเกี่ยวกับการเปลี่ยนแปลง คอลแบ็คจะรายงานการเปลี่ยนแปลงเฉพาะบน Document ที่มันถูกลงทะเบียนไว้. ยืนยันว่าคอลแบ็คถูกแนบกับ Document อินสแตนซ์ก่อนที่การเปลี่ยนแปลงจะเกิด, ไม่ใช่หลังจากนั้น.

คำถามที่พบบ่อย

ความแตกต่างระหว่าง Node กับ CompositeNode คืออะไร?

Node เป็นคลาสฐานที่ทุกองค์ประกอบของเอกสารสืบทอดมา CompositeNode ขยาย Node สำหรับองค์ประกอบที่สามารถมีลูกได้ (เช่น Body, Paragraph และ Table); ส่วนองค์ประกอบแบบ leaf เช่น 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 (หรือรากของ subtree ใดก็ได้) เพื่อเรียกใช้งานมัน.

ดูเพิ่มเติม

 ภาษาไทย