Cách làm việc với Nodes trong .NET

Cách làm việc với Nodes trong .NET

Hướng dẫn này cho thấy cách duyệt, truy vấn và sửa đổi cây nút của tài liệu Word trực tiếp trong Aspose.Words FOSS cho .NET, sử dụng Node and CompositeNode các lớp cơ sở mà Document, Section, Paragraph, Table, và mọi thành phần tài liệu khác được xây dựng trên đó. Nó bao gồm việc xác định phạm vi tìm kiếm bằng NodeType, thêm và loại bỏ các nút một cách lập trình, phản hồi các thay đổi cấu trúc, và sử dụng DocumentVisitor để duyệt dựa trên kiểu.

Hướng Dẫn Từng Bước

Bước 1: Cài đặt Gói

Aspose.Words FOSS for .NET chưa phát hành gói NuGet – hãy biên dịch thư viện từ mã nguồn thay vì. Sao chép https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git, sau đó biên dịch Aspose.Words.sln ở cấu hình Release với SDK .NET và tham chiếu assembly Aspose.Words kết quả từ dự án của bạn. Thư viện nhắm mục tiêu .NET Standard 2.0, vì vậy nó chạy trên .NET Framework 4.6.2+ và .NET 6/8/10.


Bước 2: Nhập các Lớp Cần Thiết

Thêm một chỉ thị using Aspose.Words; – Node, CompositeNode, NodeType, NodeCollection, NodeList, INodeChangingCallback và DocumentVisitor đều nằm trong không gian tên Aspose.Words cùng với Document.


Bước 3: Hiểu Node và các lớp cơ sở CompositeNode

Mỗi đối tượng trong cây tài liệu đều kế thừa từ lớp trừu tượng Node, lớp này cung cấp NodeType (xác định loại node), ParentNode (CompositeNode bao quanh), Document (tài liệu sở hữu), và PreviousSibling / NextSibling để di chuyển giữa các node cùng mức. Kiểm tra Node.IsComposite để biết một node nhất định có thể chứa các node con hay không trước khi ép kiểu. CompositeNode mở rộng Node cho các phần tử container — FirstChild, LastChild, và Count mô tả các node con trực tiếp của nó, và HasChildNodes báo cáo xem có tồn tại nào không.


Bước 4: Truy vấn các node con theo kiểu

Gọi CompositeNode.GetChildNodes(nodeType, isDeep) để lấy mọi node con của một NodeType nhất định, truyền isDeep: true để tìm kiếm toàn bộ subtree thay vì chỉ các node con trực tiếp, hoặc NodeType.Any để khớp mọi loại node bất kể kiểu. CompositeNode.GetChild(nodeType, index, isDeep) lấy một node con khớp duy nhất theo chỉ mục. Đối với các loại node cấu trúc (Document, Section, Body, Paragraph, Table, Row, Cell), các loại nội dung nội tuyến (Run, Shape, Comment), và các loại cơ cấu trường (FieldStart, FieldSeparator, FieldEnd, những cái đánh dấu ranh giới trường Word và chuyển đổi văn bản trong luồng run), truyền giá trị NodeType cụ thể xác định những gì bạn đang tìm.


Bước 5: Thực hiện các truy vấn XPath trên một Subtree

CompositeNode cũng triển khai SelectNodes(xpath) và SelectSingleNode(xpath) cho các truy vấn dựa trên XPath trên toàn subtree, trả về các kết quả dưới dạng NodeList (hoặc một Node duy nhất). CompositeNode.GetEnumerator() hỗ trợ một foreach đơn giản trên các node con trực tiếp của một node khi truy vấn XPath vượt quá nhu cầu của tác vụ.


Bước 6: Thêm, Di chuyển và Xóa các Node

Để sửa đổi cây, gọi AppendChild(newChild) hoặc PrependChild(newChild) để thêm một node ở đầu hoặc cuối danh sách các node con của container, và InsertBefore(newChild, refChild) hoặc InsertAfter(newChild, refChild) để chèn tương đối với một node con đã tồn tại. RemoveChild(oldChild) xóa một node con, và RemoveAllChildren() xóa toàn bộ các node con cùng một lúc; CompositeNode.IndexOf(child) báo cáo vị trí của node con. Trên Node tự nó, Clone(isCloneChildren) sao chép một node – tùy chọn bao gồm các node con của nó – và Remove() tách node ra khỏi cha của nó.


Bước 7: Tạo hiện thực các nút trước khi thay đổi một bộ sưu tập đang hoạt động

Việc sửa đổi một bộ sưu tập trong khi một vòng lặp foreach đang duyệt qua nó – dù đó là NodeCollection hay kết quả của GetChildNodes – sẽ gây ra lỗi. Gọi ToArray() trên bộ sưu tập trước để tạo hiện thực các nút thành một mảng cố định, sau đó duyệt qua mảng đó trong khi gọi Remove() hoặc thực hiện các thay đổi khác đối với cây.


Bước 8: Quét một cây con theo thứ tự tài liệu

Node.NextPreOrder(rootNode) và PreviousPreOrder(rootNode) duyệt qua cây theo thứ tự tài liệu, giới hạn bởi một nút gốc cho trước – một cách phổ biến để quét toàn bộ cây con từng nút mà không cần viết mã duyệt đệ quy.


Bước 9: Xử lý mọi loại nút bằng DocumentVisitor

Để xử lý nhiều loại nút khác nhau một cách có cấu trúc, kế thừa lớp trừu tượng DocumentVisitor và ghi đè các phương thức Visit*Start / Visit*End cho các loại nút quan trọng – ví dụ VisitParagraphStart / VisitParagraphEnd, VisitSectionStart / VisitSectionEnd, VisitBodyStart / VisitBodyEnd – sau đó gọi Node.Accept(visitor) trên nút gốc của cây con để thực thi. Đây là mẫu tiêu chuẩn để xuất khẩu, chuyển đổi hoặc kiểm tra một tài liệu mà không cần viết mã duyệt đệ quy tùy chỉnh cho mỗi trường hợp sử dụng.


Bước 10: Phản hồi các thay đổi cấu trúc từ mã khác

Triển khai INodeChangingCallback khi mã cần phản hồi các thao tác chèn hoặc xóa do mã khác thực hiện – bao gồm các thao tác tích hợp sẵn – không chỉ những thay đổi được thực hiện trực tiếp. Các phương thức NodeInserting(args), NodeInserted(args), NodeRemoving(args) và NodeRemoved(args) của nó mỗi đều nhận một NodeChangingArgs mô tả Node bị ảnh hưởng, cha cũ và cha mới của nó, và NodeChangingAction (Insert hoặc Remove) đã xảy ra.

Các vấn đề thường gặp và cách khắc phục

Ép kiểu một Node sang CompositeNode sẽ gây ra lỗi ép kiểu không hợp lệ Nút là loại lá – ví dụ Run or FieldStart – mà không thể chứa các nút con. Kiểm tra Node.IsComposite đầu tiên, hoặc sử dụng NodeType để xác nhận nút là loại container trước khi ép kiểu.

GetChildNodes trả về các nút con trực tiếp khi isDeep là false isDeep đã bị để lại false (hoặc bị bỏ qua khi overload mặc định là shallow). Truyền isDeep: true to GetChildNodes() để tìm kiếm toàn bộ cây con thay vì các nút con trực tiếp.

Việc sửa đổi một bộ sưu tập trong khi lặp qua nó sẽ gây ra lỗi Các nút đã được thêm hoặc xóa bên trong một foreach trên một NodeCollection hoặc kết quả của GetChildNodes. Gọi ToArray() đầu tiên để hiện thực các nút cần sửa đổi, sau đó lặp qua mảng đó trong khi thay đổi cây.

Một lớp con DocumentVisitor không được gọi cho một số nội dung Trình duyệt đã được gọi thông qua Accept() trên một node mà thực tế không chứa nội dung mục tiêu, hoặc phần tương ứng Visit* phương thức chưa được ghi đè. Gọi Accept() trên một ancestor có chứa nội dung, và ghi đè mọi Visit*Start / Visit*End cặp liên quan tới các loại node đang được xử lý.

INodeChangingCallback không được thông báo về một thay đổi callback chỉ báo cáo các thay đổi trên Document đối tượng mà nó đã được đăng ký. Xác nhận callback đã được gắn vào đúng Document instance trước khi thay đổi xảy ra, không phải sau.

Câu hỏi thường gặp

Sự khác nhau giữa Node và CompositeNode là gì?

Node là lớp cơ sở mà mọi phần tử tài liệu đều kế thừa. CompositeNode mở rộng Node cho các phần tử có thể chứa con (chẳng hạn Body, Paragraph, và Table); các phần tử lá như Run kế thừa trực tiếp từ Node và không thể chứa con.

Làm sao tôi tìm tất cả các node có kiểu cụ thể trong một tài liệu?

Gọi CompositeNode.GetChildNodes(nodeType, isDeep) trên node làm gốc của việc tìm kiếm – thường là Document tự nó – truyền NodeType và isDeep: true mục tiêu để tìm trong toàn bộ subtree, không chỉ các con trực tiếp.

Làm sao tôi có thể xóa node một cách an toàn khi đang lặp?

Đầu tiên thu thập các node cần xóa vào một mảng – ví dụ bằng NodeCollection.ToArray() – sau đó lặp qua mảng đó và gọi Remove() trên mỗi node, thay vì sửa đổi collection đang hoạt động khi một foreach đang lặp qua nó.

Các node FieldStart, FieldSeparator và FieldEnd là gì?

Chúng là các giá trị NodeType đánh dấu cơ cấu của một trường Word được nhúng trong luồng run: FieldStart và FieldEnd ràng buộc trường, và FieldSeparator tách mã trường ra khỏi kết quả đang hiển thị hiện tại.

Làm sao để tôi xử lý mọi đoạn văn, bảng và run trong một tài liệu?

Tạo lớp con DocumentVisitor, ghi đè các phương thức Visit*Start / Visit*End cho các loại nút cần thiết, sau đó gọi Accept(visitor) trên Document (hoặc bất kỳ gốc cây con nào) để chạy nó.

Xem thêm

 Tiếng Việt