Aspose.Words Document Object Model (DOM)
Aspose.Words Document Object Model (DOM)是 Word 文檔的內存表示。 Aspose.Words DOM 讓您可以程式設計地閱讀、操控並修改 Word 文檔的內容與格式。
本節描述Aspose.Words和DOM的主要類別及其關係。 透過使用 Aspose.Words DOM 類別,您可以取得對文件元素及格式的程式化存取。
建立 {#create-a-document-objects-tree} Document
物件樹
當一篇文件被讀進 Aspose.Words DOM 中時,會建立一個物件樹,而該文件的不同類別元素也會各自有自己的 DOM 樹形體,具有各樣的屬性。
建立文檔節點樹
當 Aspose.Words 將 Word 文檔載入記憶體時,它會建立不同類型的物件來代表各種文檔元素。 每個文本、段落、表格或節的運行都是一個節點,而整個文件也是節點。 Aspose.Words定義了每個文件節點類型的一類。
Aspose.Words中的ドキュメントツリー跟隨合成設計模式。
“-所有節點類別最終都派生自 Node 類別,它是 Aspose.Words 的基底類別 Document Object Model。”
- 可包含其他節點的節點,例如Section或Paragraph,從CompositeNode類別中派生,並最終從Node類別中派生。
下方提供的圖示顯示了節點類之間的繼承關係,類別為:Aspose.Words Document Object Model (DOM). 抽象類別的名稱以斜體字樣表示。
我們來看一個例子。 接下來這張圖是顯示一種 Microsoft Word 文檔,上面有不同類型的內容。
在讀取上述文件進入 Aspose.Words DOM 時,物件樹會如下圖所示地創建出來。
Document、Section、Paragraph、Table、Shape、Run,及圖中其他所有省略符號都是 Aspose.Words 個物件,這些物件代表 Word 文檔的元件。
取得一隻 Node
型
雖然 Node 類別足以讓不同節點彼此區分,但是 Aspose.Words 提供了 NodeType 列舉以簡化一些 API 任務,例如選擇特定類別的節點。
每个节点的类型可以通过 NodeType 属性来获取。 此屬性返回一 NodeType 列舉值。 例如,由 Paragraph 類別表示的段落節點會回傳 NodeType.Paragraph ,而由 Table 類別表示的表格節點則會回傳 NodeType.Table 。
以下示例說明如何透過 NodeType 列舉來取得節點類型:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
Document doc = new Document(); | |
// Returns NodeType.Document | |
NodeType type = doc.NodeType; |
Document Tree 导航
Aspose.Words 代表文件作為節點樹,這允許您在節點之間導航。 本節描述如何在 Aspose.Words 中探索和導航 문서樹。
當你在文件 탐색器中打開早先所呈現的範例文件時,節點樹會出現和 Aspose.Words 中的表示完全相同。
文件節點關係
樹狀圖中的節點之間有關係:
-一個包含另一個節點的節點是一個 parent.
- 包含在父節點中的節點是 child. 子節點與相同的父節點 sibling 節點。
- root節點總是會是 Document 節點。
可包含其他節點的節點源自 CompositeNode 類別,而所有節點最終源自 Node 類別。 這兩個基本類別提供了用於樹結構導向與修改的常見方法和屬性。
接下來的 UML 物件圖示出此範例文件中幾個節點及其透過父、子及兄弟屬性的相互關係。
文書是節點所有者
一個節點總是屬於某一個特定的文件,即使它剛被建立或從樹上移除,因為具有重要性的全文件結構(例如樣式和清單)都儲存在 Document 節點中。 例如,不可能存在沒有 Paragraph 的 Document ,因為每個段落都有分配的樣式,而這些樣式被定義為文件的全球樣式。 這個規則是在建立新節點時使用的。 直接將新的 Paragraph 加入到 DOM 中需要傳送一個物件給建構子。
當以 DocumentBuilder 建立新段落時,建構器總是透過 DocumentBuilder.Document 屬性將其連結到 Document 類別。
程式碼範例示出了當建立任何節點時,必須定義將擁有該節點的文件:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
// Open a file from disk. | |
Document doc = new Document(); | |
// Creating a new node of any type requires a document passed into the constructor. | |
Paragraph para = new Paragraph(doc); | |
// The new paragraph node does not yet have a parent. | |
Console.WriteLine("Paragraph has no parent node: " + (para.ParentNode == null)); | |
// But the paragraph node knows its document. | |
Console.WriteLine("Both nodes' documents are the same: " + (para.Document == doc)); | |
// The fact that a node always belongs to a document allows us to access and modify | |
// Properties that reference the document-wide data such as styles or lists. | |
para.ParagraphFormat.StyleName = "Heading 1"; | |
// Now add the paragraph to the main text of the first section. | |
doc.FirstSection.Body.AppendChild(para); | |
// The paragraph node is now a child of the Body node. | |
Console.WriteLine("Paragraph has a parent node: " + (para.ParentNode != null)); |
親节点
每個節點都有個由 ParentNode 屬性指定的父節點。 在以下情況下,節點沒有父節點,也就是 ParentNode 是空值:
- 這節點剛好被建立,還沒有被加入到樹中。
- 該節點已從樹中移除。
- 這是一個根Document節,它總是有一個null的父節。
您可以透過呼叫 Remove 方法從父節點中移除一個節點。以下範例示意了如何存取父節點:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
// Create a new empty document. It has one section. | |
Document doc = new Document(); | |
// The section is the first child node of the document. | |
Node section = doc.FirstChild; | |
// The section's parent node is the document. | |
Console.WriteLine("Section parent is the document: " + (doc == section.ParentNode)); |
子節點
存取子節點的最有效方式是透過 CompositeNode 的 FirstChild 和 LastChild 屬性,它們分別會回傳第一個和最後一個的節點。 如果沒有子節點,這些屬性會返回 null。
CompositeNode 也提供 GetChildNodes 方法,讓您可以索引或列舉訪問子節點。 ChildNodes屬性是一個 canlı koleksiyonu nodları,這意味著每當文書被改變、例如 nodlar 移除或添加時,ChildNodes koleksiyonu otomatik olarak更新。
如果一個節點沒有子節點,則 ChildNodes 屬性會返回空集合。 您可以透過 CompositeNode 的 HasChildNodes 屬性來檢查是否包含任何子節點。
接下來的程式碼範例示範了如何透過由 ChildNodes
集合提供的列舉器,枚數 CompositeNode
的直接子節點:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
Document doc = new Document(); | |
Paragraph paragraph = (Paragraph)doc.GetChild(NodeType.Paragraph, 0, true); | |
NodeCollection children = paragraph.ChildNodes; | |
foreach (Node child in children) | |
{ | |
// Paragraph may contain children of various types such as runs, shapes and so on. | |
if (child.NodeType.Equals(NodeType.Run)) | |
{ | |
// Say we found the node that we want, do something useful. | |
Run run = (Run)child; | |
Console.WriteLine(run.Text); | |
} | |
} |
接下來的程式碼範例示範如何使用索引存取枚數 CompositeNode
的即時子節點:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
Document doc = new Document(); | |
Paragraph paragraph = (Paragraph)doc.GetChild(NodeType.Paragraph, 0, true); | |
NodeCollection children = paragraph.ChildNodes; | |
for (int i = 0; i < children.Count; i++) | |
{ | |
Node child = children[i]; | |
// Paragraph may contain children of various types such as runs, shapes and so on. | |
if (child.NodeType.Equals(NodeType.Run)) | |
{ | |
// Say we found the node that we want, do something useful. | |
Run run = (Run)child; | |
Console.WriteLine(run.Text); | |
} | |
} |
子節點
你可以透過分別使用 PreviousSibling 和 NextSibling 屬性,取得某個節點前或後的節點。 如果一個節點是它父節點的最後子節點,那這個 NextSibling 屬性就是 null。 不過,若該節點是其父節點的第一個孩子,則 PreviousSibling 屬性為 null。
接下來的程式碼範例示範了如何有效地造訪一個複合節點的所有直接及間接子節點:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
public static void RecurseAllNodes() | |
{ | |
// The path to the documents directory. | |
string dataDir = RunExamples.GetDataDir_WorkingWithNode(); | |
// Open a document. | |
Document doc = new Document(dataDir + "Node.RecurseAllNodes.doc"); | |
// Invoke the recursive function that will walk the tree. | |
TraverseAllNodes(doc); | |
} | |
/// <summary> | |
/// A simple function that will walk through all children of a specified node recursively | |
/// And print the type of each node to the screen. | |
/// </summary> | |
public static void TraverseAllNodes(CompositeNode parentNode) | |
{ | |
// This is the most efficient way to loop through immediate children of a node. | |
for (Node childNode = parentNode.FirstChild; childNode != null; childNode = childNode.NextSibling) | |
{ | |
// Do some useful work. | |
Console.WriteLine(Node.NodeTypeToString(childNode.NodeType)); | |
// Recurse into the node if it is a composite node. | |
if (childNode.IsComposite) | |
TraverseAllNodes((CompositeNode)childNode); | |
} | |
} |
對子節點和父節點的打開存取
到目前為止,我們已討論回傳基底類型的屬性– Node 或 CompositeNode。 但在有時你可能需要將值投射到特定的節點類別,例如 Run 或 Paragraph。 就是說,你無法在與複合體Aspose.WordsDOM一起工作時完全避免投射。
為了減少型式轉換的需要,大多數 Aspose.Words 類別提供屬性和集合以提供強型別存取。 打字存取有三个基本模式。
- 父節點會公開 FirstXXX 和 LastXXX 屬性。 例如,Document具有 FirstSection 和 LastSection 的屬性。 同樣的,Table有性質如FirstRow、LastRow及更多。
- 父節點公開一個類型集合的子節點,例如 Document.Sections、Body.Paragraphs 和其他。
- 子節點提供了對父節點的定型存取,例如 Run.ParentParagraph、Paragraph.ParentSection 和其他。
類別屬性僅提供方便的捷徑,有時比從 Node.ParentNode 和 CompositeNode.FirstChild 繼承的一般屬性更易訪問。
以下代碼示例演示了如何使用型別化屬性來存取 dokumen樹中的節點:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
Document doc = new Document(); | |
Section section = doc.FirstSection; | |
// Quick typed access to the Body child node of the Section. | |
Body body = section.Body; | |
// Quick typed access to all Table child nodes contained in the Body. | |
TableCollection tables = body.Tables; | |
foreach (Table table in tables) | |
{ | |
// Quick typed access to the first row of the table. | |
if (table.FirstRow != null) | |
table.FirstRow.Remove(); | |
// Quick typed access to the last row of the table. | |
if (table.LastRow != null) | |
table.LastRow.Remove(); | |
} |