Aspose.Words Document Object Model (DOM)
Aspose.Words Document Object Model (DOM) to reprezentacja dokumentu Word w pamięci. Aspose.Words DOM umożliwia programowe odczytywanie, manipulowanie i modyfikowanie zawartości i formatowania dokumentu programu Word.
W tej sekcji opisano główne klasy Aspose.Words DOM i ich relacje. Korzystając z klas Aspose.Words DOM, można uzyskać programowy dostęp do elementów dokumentu i formatowania.
Utwórz drzewo obiektów Document
Kiedy dokument jest wczytywany do Aspose.Words DOM, budowane jest drzewo obiektów, a różne typy elementów dokumentu źródłowego mają własne obiekty drzewa DOM o różnych właściwościach.
Zbuduj drzewo węzłów dokumentów
Kiedy Aspose.Words wczytuje dokument Word do pamięci, tworzy obiekty różnych typów, które reprezentują różne elementy dokumentu. Każdy ciąg tekstu, akapitu, tabeli lub sekcji jest węzłem i nawet sam dokument jest węzłem. Aspose.Words definiuje klasę dla każdego typu węzła dokumentu.
Drzewo dokumentów w Aspose.Words jest zgodne ze złożonym wzorcem projektowym:
- Wszystkie klasy węzłów ostatecznie wywodzą się z klasy Node, która jest klasą bazową w formacie Aspose.Words Document Object Model.
- Węzły, które mogą zawierać inne węzły, na przykład Section lub Paragraph, wywodzą się z klasy CompositeNode, która z kolei wywodzi się z klasy Node.
Poniższy diagram przedstawia dziedziczenie pomiędzy klasami węzłów Aspose.Words Document Object Model (DOM). Nazwy klas abstrakcyjnych podano kursywą.
Node
.
Spójrzmy na przykład. Poniższy obraz przedstawia dokument Microsoft Word z różnymi typami treści.
Podczas wczytywania powyższego dokumentu do Aspose.Words DOM tworzone jest drzewo obiektów, jak pokazano na schemacie poniżej.
Document, Section, Paragraph, Table, Shape, Run i wszystkie inne elipsy na diagramie to obiekty Aspose.Words reprezentujące elementy dokumentu Word.
Zdobądź plik {#get-a-node-type} typu Node
Chociaż klasa Node jest wystarczająca do rozróżnienia różnych węzłów, Aspose.Words udostępnia wyliczenie NodeType w celu uproszczenia niektórych zadań API, takich jak wybieranie węzłów określonego typu.
Typ każdego węzła można uzyskać za pomocą właściwości NodeType. Ta właściwość zwraca wartość wyliczenia NodeType. Na przykład węzeł akapitu reprezentowany przez klasę Paragraph zwraca NodeType.Paragraph, a węzeł tabeli reprezentowany przez klasę Table zwraca NodeType.Table.
Poniższy przykład pokazuje, jak uzyskać typ węzła za pomocą wyliczenia 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; |
Nawigacja po drzewie dokumentów
Aspose.Words reprezentuje dokument jako drzewo węzłów, które umożliwia nawigację pomiędzy węzłami. W tej sekcji opisano, jak eksplorować i poruszać się po drzewie dokumentów w Aspose.Words.
Po otwarciu zaprezentowanego wcześniej przykładowego dokumentu w Eksploratorze dokumentów drzewo węzłów wygląda dokładnie tak, jak jest reprezentowane w Aspose.Words.
Relacje węzła dokumentu
Węzły w drzewie mają między sobą relacje:
- Węzeł zawierający inny węzeł to parent.
- Węzeł zawarty w węźle nadrzędnym to child. Węzły podrzędne tego samego rodzica to węzły sibling.
- Węzeł root jest zawsze węzłem Document.
Węzły, które mogą zawierać inne węzły, wywodzą się z klasy CompositeNode, a wszystkie węzły ostatecznie wywodzą się z klasy Node. Te dwie klasy podstawowe zapewniają wspólne metody i właściwości do nawigacji i modyfikacji struktury drzewa.
Poniższy diagram obiektów UML przedstawia kilka węzłów przykładowego dokumentu i ich wzajemne relacje poprzez właściwości nadrzędne, podrzędne i równorzędne:
Dokument jest właścicielem węzła
Węzeł zawsze należy do konkretnego dokumentu, nawet jeśli został właśnie utworzony lub usunięty z drzewa, ponieważ istotne struktury całego dokumentu, takie jak style i listy, są przechowywane w węźle Document. Na przykład nie jest możliwe utworzenie Paragraph bez Document, ponieważ każdy akapit ma przypisany styl, który jest zdefiniowany globalnie dla dokumentu. Reguła ta jest używana podczas tworzenia nowych węzłów. Dodanie nowego Paragraph bezpośrednio do DOM wymaga przekazania obiektu dokumentu do konstruktora.
Tworząc nowy akapit przy użyciu DocumentBuilder, konstruktor zawsze ma powiązaną z nim klasę Document poprzez właściwość DocumentBuilder.Document.
Poniższy przykład kodu pokazuje, że podczas tworzenia dowolnego węzła zawsze zdefiniowany jest dokument, który będzie właścicielem węzła:
// 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)); |
Węzeł nadrzędny
Każdy węzeł ma rodzica określonego przez właściwość ParentNode. Węzeł nie ma węzła nadrzędnego, co oznacza, że ParentNode ma wartość null w następujących przypadkach:
- Węzeł został właśnie utworzony i nie został jeszcze dodany do drzewa.
- Węzeł został usunięty z drzewa.
- To jest główny węzeł Document, który zawsze ma zerowy węzeł nadrzędny.
Możesz usunąć węzeł z jego rodzica, wywołując metodę Remove. Poniższy przykładowy kod pokazuje, jak uzyskać dostęp do węzła nadrzędnego:
// 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)); |
Węzły podrzędne
Najbardziej efektywnym sposobem uzyskania dostępu do węzłów podrzędnych CompositeNode jest użycie właściwości FirstChild i LastChild, które zwracają odpowiednio pierwszy i ostatni węzeł podrzędny. Jeśli nie ma żadnych węzłów podrzędnych, te właściwości zwracają null.
CompositeNode zapewnia również metodę GetChildNodes umożliwiającą indeksowany lub wyliczeniowy dostęp do węzłów podrzędnych. Właściwość ChildNodes to zbiór węzłów na żywo, co oznacza, że przy każdej zmianie dokumentu, na przykład podczas usuwania lub dodawania węzłów, kolekcja ChildNodes jest automatycznie aktualizowana.
Jeśli węzeł nie ma dziecka, właściwość ChildNodes zwraca pustą kolekcję. Możesz sprawdzić, czy CompositeNode zawiera jakiekolwiek węzły podrzędne, korzystając z właściwości HasChildNodes.
Poniższy przykład kodu pokazuje, jak wyliczyć bezpośrednie węzły podrzędne CompositeNode
przy użyciu modułu wyliczającego dostarczonego przez kolekcję ChildNodes
:
// 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); | |
} | |
} |
Poniższy przykład kodu pokazuje, jak wyliczyć bezpośrednie węzły podrzędne CompositeNode
przy użyciu dostępu indeksowanego:
// 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); | |
} | |
} |
Węzły rodzeństwa
Można uzyskać węzeł bezpośrednio poprzedzający lub następujący po określonym węźle, korzystając odpowiednio z właściwości PreviousSibling i NextSibling. Jeśli węzeł jest ostatnim dzieckiem swojego rodzica, wówczas właściwością NextSibling jest null. I odwrotnie, jeśli węzeł jest pierwszym dzieckiem swojego rodzica, właściwością PreviousSibling jest null.
Poniższy przykład kodu pokazuje, jak efektywnie odwiedzać wszystkie bezpośrednie i pośrednie węzły podrzędne węzła złożonego:
// 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); | |
} | |
} |
Wpisany dostęp do węzłów podrzędnych i nadrzędnych
Do tej pory omówiliśmy właściwości zwracające jeden z typów bazowych – Node lub CompositeNode. Czasami jednak zdarzają się sytuacje, w których może być konieczne rzutowanie wartości na konkretną klasę węzła, taką jak Run lub Paragraph. Oznacza to, że nie można całkowicie odejść od odlewania podczas pracy z plikiem Aspose.Words DOM, który jest złożony.
Aby zmniejszyć potrzebę rzutowania, większość klas Aspose.Words udostępnia właściwości i kolekcje zapewniające dostęp o jednoznacznie określonym typie. Istnieją trzy podstawowe wzorce dostępu wpisywanego:
- Węzeł nadrzędny udostępnia wpisane właściwości FirstXXX i LastXXX. Na przykład Document ma właściwości FirstSection i LastSection. Podobnie Table ma właściwości takie jak FirstRow, LastRow i inne.
- Węzeł nadrzędny udostępnia wpisaną kolekcję węzłów podrzędnych, takich jak Document.Sections, Body.Paragraphs i inne.
- Węzeł podrzędny zapewnia dostęp do swojego rodzica za pomocą wpisania, taki jak Run.ParentParagraph, Paragraph.ParentSection i inne.
Wpisane właściwości to jedynie przydatne skróty, które czasami zapewniają łatwiejszy dostęp niż właściwości ogólne odziedziczone z Node.ParentNode i CompositeNode.FirstChild.
Poniższy przykład kodu pokazuje, jak używać wpisanych właściwości w celu uzyskania dostępu do węzłów drzewa dokumentu:
// 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(); | |
} |