Cara Bekerja dengan Node di .NET
Panduan ini menunjukkan cara menelusuri, mengkueri, dan memodifikasi pohon node dokumen Word secara langsung di Aspose.Words FOSS untuk .NET, menggunakan Node and CompositeNode kelas dasar yang Document, Section, Paragraph, Table, dan setiap elemen dokumen lainnya dibangun di atasnya. Ini mencakup pembatasan pencarian berdasarkan NodeType, menambahkan dan menghapus node secara programatik, merespons perubahan struktural, dan menggunakan DocumentVisitor untuk penelusuran berbasis tipe.
Panduan Langkah demi Langkah
Langkah 1: Instal Paket
Aspose.Words FOSS for .NET belum menerbitkan paket NuGet – bangun pustaka dari sumbernya saja. Kloning https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git, lalu bangun Aspose.Words.sln dalam konfigurasi Release dengan SDK .NET dan referensikan assembly Aspose.Words yang dihasilkan dari proyek Anda. Pustaka menargetkan .NET Standard 2.0, sehingga dapat dijalankan di .NET Framework 4.6.2+ dan .NET 6/8/10.
Langkah 2: Impor Kelas yang Diperlukan
Tambahkan arahan using Aspose.Words; – Node, CompositeNode, NodeType, NodeCollection, NodeList, INodeChangingCallback, dan DocumentVisitor semuanya berada di namespace Aspose.Words bersama Document.
Langkah 3: Memahami Node dan Kelas Dasar CompositeNode
Setiap objek dalam pohon dokumen diturunkan dari kelas abstrak Node, yang menyediakan NodeType (mengidentifikasi jenis node), ParentNode (yang membungkus CompositeNode), Document (dokumen pemilik), dan PreviousSibling / NextSibling untuk berpindah antar node pada tingkat yang sama. Periksa Node.IsComposite untuk mengetahui apakah node tertentu dapat berisi anak sebelum melakukan casting. CompositeNode memperluas Node untuk elemen kontainer — FirstChild, LastChild, dan Count menjelaskan anak langsungnya, dan HasChildNodes melaporkan apakah ada yang ada.
Langkah 4: Kueri Anak berdasarkan Tipe
Panggil CompositeNode.GetChildNodes(nodeType, isDeep) untuk mengambil setiap anak dari NodeType tertentu, dengan menyertakan isDeep: true untuk mencari seluruh subpohon bukan hanya anak langsung, atau NodeType.Any untuk mencocokkan setiap tipe node tanpa memperhatikan jenisnya. CompositeNode.GetChild(nodeType, index, isDeep) mengambil satu anak yang cocok berdasarkan indeks. Untuk tipe node struktural (Document, Section, Body, Paragraph, Table, Row, Cell), tipe konten inline (Run, Shape, Comment), dan tipe mesin field (FieldStart, FieldSeparator, FieldEnd, yang menandai batas bidang Word dan teks saklar dalam aliran run), berikan nilai NodeType spesifik yang mengidentifikasi apa yang Anda cari.
Langkah 5: Jalankan Kueri XPath di Seluruh Subpohon
CompositeNode juga mengimplementasikan SelectNodes(xpath) dan SelectSingleNode(xpath) untuk kueri berbasis XPath di seluruh subpohon, mengembalikan hasil yang cocok sebagai NodeList (atau satu Node). CompositeNode.GetEnumerator() mendukung foreach sederhana atas anak langsung sebuah node ketika kueri XPath lebih dari yang diperlukan.
Langkah 6: Tambah, Pindah, dan Hapus Node
Untuk memodifikasi pohon, panggil AppendChild(newChild) atau PrependChild(newChild) untuk menambahkan node di awal atau akhir anak sebuah kontainer, serta InsertBefore(newChild, refChild) atau InsertAfter(newChild, refChild) untuk menyisipkan relatif terhadap anak yang sudah ada. RemoveChild(oldChild) menghapus satu anak, dan RemoveAllChildren() mengosongkan semua anak sekaligus; CompositeNode.IndexOf(child) melaporkan posisi sebuah anak. Pada Node itu sendiri, Clone(isCloneChildren) menyalin sebuah node — secara opsional termasuk anak-anaknya — dan Remove() melepaskan node dari induknya.
Langkah 7: Materialisasikan Node Sebelum Mengubah Koleksi yang Aktif
Memodifikasi sebuah koleksi saat sebuah loop foreach sedang mengiterasinya – baik itu NodeCollection atau hasil dari GetChildNodes – akan menyebabkan error. Panggil ToArray() pada koleksi terlebih dahulu untuk mematerialisasikan node menjadi array tetap, kemudian iterasi array tersebut sambil memanggil Remove() atau melakukan perubahan lain pada pohon.
Langkah 8: Pindai Subpohon dalam Urutan Dokumen
Node.NextPreOrder(rootNode) dan PreviousPreOrder(rootNode) melangkah melalui pohon dalam urutan dokumen, dibatasi oleh node akar tertentu – cara umum untuk memindai seluruh subpohon node demi node tanpa menulis kode traversal rekursif.
Langkah 9: Proses Setiap Tipe Node dengan DocumentVisitor
Untuk memproses banyak tipe node yang berbeda secara terstruktur, buat subclass dari kelas abstrak DocumentVisitor dan timpa metode Visit*Start / Visit*End untuk tipe node yang penting – misalnya VisitParagraphStart / VisitParagraphEnd, VisitSectionStart / VisitSectionEnd, VisitBodyStart / VisitBodyEnd – kemudian panggil Node.Accept(visitor) pada akar subpohon untuk menjalankannya. Ini adalah pola standar untuk mengekspor, mentransformasi, atau memeriksa sebuah dokumen tanpa menulis traversal rekursif khusus untuk setiap kasus penggunaan.
Langkah 10: Bereaksi terhadap Perubahan Struktural dari Kode Lain
Implementasikan INodeChangingCallback ketika kode perlu bereaksi terhadap penyisipan atau penghapusan yang dilakukan oleh kode lain – termasuk operasi bawaan – bukan hanya perubahan yang dilakukan secara langsung. Metode NodeInserting(args), NodeInserted(args), NodeRemoving(args), dan NodeRemoved(args) masing-masing menerima sebuah NodeChangingArgs yang menjelaskan Node yang terpengaruh, orang tua lama dan baru, serta NodeChangingAction (Insert atau Remove) yang terjadi.
Masalah Umum dan Solusi
Mencasting Node ke CompositeNode menghasilkan kesalahan cast yang tidak valid Node tersebut adalah tipe daun – misalnya Run or FieldStart – yang tidak dapat memiliki anak. Periksa Node.IsComposite dulu, atau gunakan NodeType untuk memastikan node adalah tipe kontainer sebelum melakukan casting.
GetChildNodes mengembalikan anak langsung ketika isDeep bernilai false isDeep dibiarkan false (atau dihilangkan dimana overload defaultnya shallow). Lewati isDeep: true to GetChildNodes() untuk mencari seluruh subtree alih-alih anak langsung.
Memodifikasi koleksi saat mengiterasinya menyebabkan kesalahan Node ditambahkan atau dihapus di dalam sebuah foreach di atas sebuah NodeCollection atau hasil dari GetChildNodes. Panggil ToArray() pertama untuk mematerialisasi node yang akan dimodifikasi, kemudian iterasi array tersebut sambil memutasi pohonnya.
Sebuah subclass DocumentVisitor tidak dipanggil untuk beberapa konten Pengunjung dipanggil melalui Accept() pada node yang sebenarnya tidak berisi konten target, atau yang bersesuaian Visit* metode tidak ditimpa. Panggil Accept() pada nenek moyang yang berisi konten, dan timpa setiap Visit*Start / Visit*End pasangan yang relevan dengan tipe node yang sedang diproses.
INodeChangingCallback tidak diberi tahu tentang perubahan Callback hanya melaporkan perubahan pada Document yang terdaftar padanya. Pastikan callback terpasang pada yang tepat Document instance sebelum perubahan terjadi, bukan setelahnya.
Pertanyaan yang Sering Diajukan
Apa perbedaan antara Node dan CompositeNode?
Node adalah kelas dasar yang menjadi turunan semua elemen dokumen. CompositeNode memperluas Node untuk elemen yang dapat memiliki anak (seperti Body, Paragraph, dan Table); elemen daun seperti Run diturunkan langsung dari Node dan tidak dapat menampung anak.
Bagaimana cara menemukan semua node dengan tipe tertentu dalam dokumen?
Panggil CompositeNode.GetChildNodes(nodeType, isDeep) pada node yang menjadi akar pencarian – seringkali Document itu sendiri – dengan memberikan NodeType target dan isDeep: true untuk mencari seluruh subpohon, bukan hanya anak langsung.
Bagaimana cara menghapus node dengan aman saat melakukan iterasi?
Kumpulkan node yang akan dihapus ke dalam sebuah array terlebih dahulu – misalnya dengan NodeCollection.ToArray() – kemudian iterasi array tersebut dan panggil Remove() pada setiap node, alih-alih memodifikasi koleksi langsung saat foreach sedang mengiterasinya.
Apa itu node FieldStart, FieldSeparator, dan FieldEnd?
Mereka adalah nilai NodeType yang menandai mekanisme bidang Word yang disematkan dalam aliran run: FieldStart dan FieldEnd mengikat bidang tersebut, dan FieldSeparator memisahkan kode bidang dari hasil yang saat ini ditampilkan.
Bagaimana saya memproses setiap paragraf, tabel, dan run dalam dokumen?
Buat subclass DocumentVisitor, timpa metode Visit*Start / Visit*End untuk tipe node yang diperlukan, lalu panggil Accept(visitor) pada Document (atau akar subtree mana pun) untuk menjalankannya.