Aspose.Words Документ Обектен Модел (DOM)
Aspose.Words обектен модел на документ (DOM) е представяне в паметта на документ Word. Aspose.Words DOM ви позволява програмно да четете, манипулирате и променяте съдържанието и форматирането на Word документ.
Този раздел описва основните класове Aspose.Words DOM и техните връзки. Използвайки класовете Aspose.Words DOM, можете да получите програмен достъп до елементите на документа и форматирането.
Създаване На Дърво На Обекта На Документа
Когато даден документ бъде прочетен в Aspose.Words DOM, тогава се изгражда дърво на обектите и различните типове елементи на документа източник имат свои собствени обекти DOM дърво с различни свойства.
Изграждане На Документ Възли Дърво
Когато Aspose.Words прочете документ Word в паметта, той създава обекти от различни типове, които представляват различни елементи на документа. Всяко изпълнение на текст, абзац, таблица или раздел е възел и дори самият документ е възел. Aspose.Words дефинира клас за всеки тип възел на документ.
Документното дърво в Aspose.Words следва модела на композитен дизайн:
- Всички класове възли в крайна сметка произхождат от класа Node, който е базовият клас в обектния модел Aspose.Words на документа.
- Възли, които могат да съдържат други възли, например Section или Paragraph, произхождат от клас CompositeNode, който на свой ред произлиза от клас Node.
Диаграмата по-долу показва наследяването между класовете на възлите на обектния модел на документа Aspose.Words (DOM). Имената на абстрактните класове са в курсив.

Node
класа.
Нека разгледаме един пример. Следващото изображение показва 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-C | |
System::SharedPtr<Document> doc = System::MakeObject<Document>(); | |
// Returns NodeType.Document | |
NodeType type = doc->get_NodeType(); |
Навигация В Дървото На Документите
Aspose.Words представлява документ като дърво на възлите, което ви позволява да се придвижвате между възлите. Този раздел описва как да проучите и навигирате в дървото с документи в Aspose.Words.
Когато отворите примерния документ, представен по-рано в изследователя на документи, дървото на възлите се появява точно както е представено в Aspose.Words.

Документ Връзки Възел
Върховете в дървото имат връзки помежду си.:
- Възел, съдържащ друг възел, е parent.
- Възелът, съдържащ се в родителския възел, е child. Детски възли на същия Родител са sibling възли.
- root възел винаги е Document възел.
Възлите, които могат да съдържат други възли, произхождат от класа CompositeNode и всички възли в крайна сметка произлизат от класа Node. Тези два базови класа осигуряват общи методи и свойства за навигация и модификация на дървовидната структура.
Следващата диаграма UML показва няколко възли от примерния документ и техните връзки помежду си чрез свойствата родител, дете и брат / сестра.:

Документ е собственик на възел
Всеки възел винаги принадлежи към определен документ, дори ако той току-що е бил създаден или премахнат от дървото, тъй като жизненоважни структури, обхващащи целия документ, като стилове и списъци, се съхраняват във възела Document. Например не е възможно да има Paragraph Без Document, защото всеки абзац има присвоен стил, който е дефиниран глобално за документа. Това правило се използва при създаването на нови възли. Добавянето на нов Paragraph директно към DOM изисква документ обект, предаден на конструктора.
Когато създавате нов абзац, използвайки DocumentBuilder, строителят винаги има клас Document, свързан с него чрез свойството DocumentBuilder.Document.
Следващият пример за код показва, че когато създавате който и да е възел, винаги е дефиниран документ, който ще притежава възела.:
For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C | |
// Open a file from disk. | |
System::SharedPtr<Document> doc = System::MakeObject<Document>(); | |
// Creating a new node of any type requires a document passed into the constructor. | |
System::SharedPtr<Paragraph> para = System::MakeObject<Paragraph>(doc); | |
// The new paragraph node does not yet have a parent. | |
std::cout << "Paragraph has no parent node: " << System::ObjectExt::Box<bool>((para->get_ParentNode() == nullptr))->ToString().ToUtf8String() << std::endl; | |
// But the paragraph node knows its document. | |
std::cout << "Both nodes' documents are the same: " << System::ObjectExt::Box<bool>((para->get_Document() == doc))->ToString().ToUtf8String() << std::endl; | |
// 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->get_ParagraphFormat()->set_StyleName(u"Heading 1"); | |
// Now add the paragraph to the main text of the first section. | |
doc->get_FirstSection()->get_Body()->AppendChild(para); | |
// The paragraph node is now a child of the Body node. | |
std::cout << "Paragraph has a parent node: " << System::ObjectExt::Box<bool>((para->get_ParentNode() != nullptr))->ToString().ToUtf8String() << std::endl; |
Родителски Възел
Всеки възел има Родител, посочен от свойството ParentNode. Един възел няма родителски възел, т. е. ParentNode е нулев в следните случаи::
- Той е създаден и все още не е добавен към дървото.
- Възелът е премахнат от дървото.
- Това е корен Document възел, който винаги има нулев родителски възел.
Можете да премахнете възел от неговия родител, като извикате метода Remove.Следващият пример за код показва как да получите достъп до родителския възел:
For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C | |
// Create a new empty document. It has one section. | |
System::SharedPtr<Document> doc = System::MakeObject<Document>(); | |
// The section is the first child node of the document. | |
System::SharedPtr<Node> section = doc->get_FirstChild(); | |
// The section's parent node is the document. | |
std::cout << "Section parent is the document: " << System::ObjectExt::Box<bool>((doc == section->get_ParentNode()))->ToString().ToUtf8String() << std::endl; |
Детски Възли
Най-ефективният начин за достъп до детски възли на а CompositeNode е чрез свойствата FirstChild и LastChild, които връщат съответно първия и последния Детски възли. Ако няма детски възли, тези свойства се връщат null.
CompositeNode
Ако даден възел няма дете, тогава свойството ChildNodes връща празна колекция. Можете да проверите дали CompositeNode съдържа детски възли, като използвате свойството HasChildNodes.
Следният пример за код показва как да се изброят непосредствени Детски възли на CompositeNode
, като се използва изброителят, предоставен от колекцията ChildNodes
:
For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C | |
System::SharedPtr<Document> doc = System::MakeObject<Document>(); | |
System::SharedPtr<Paragraph> paragraph = System::DynamicCast<Paragraph>(doc->GetChild(NodeType::Paragraph, 0, true)); | |
System::SharedPtr<NodeCollection> children = paragraph->get_ChildNodes(); | |
for (System::SharedPtr<Node> child : System::IterateOver(children)) | |
{ | |
if (System::ObjectExt::Equals(child->get_NodeType(), NodeType::Run)) | |
{ | |
// Say we found the node that we want, do something useful. | |
System::SharedPtr<Run> run = System::DynamicCast<Run>(child); | |
std::cout << run->get_Text().ToUtf8String() << std::endl; | |
} | |
} |
Следният пример за код показва как да се изброят непосредствени Детски възли на CompositeNode
, като се използва индексиран достъп:
For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C | |
System::SharedPtr<Document> doc = System::MakeObject<Document>(); | |
System::SharedPtr<Paragraph> paragraph = System::DynamicCast<Paragraph>(doc->GetChild(NodeType::Paragraph, 0, true)); | |
System::SharedPtr<NodeCollection> children = paragraph->get_ChildNodes(); | |
for (int32_t i = 0; i < children->get_Count(); i++) | |
{ | |
System::SharedPtr<Node> child = children->idx_get(i); | |
// Paragraph may contain children of various types such as runs, shapes and so on. | |
if (System::ObjectExt::Equals(child->get_NodeType(), NodeType::Run)) | |
{ | |
// Say we found the node that we want, do something useful. | |
System::SharedPtr<Run> run = System::DynamicCast<Run>(child); | |
std::cout << run->get_Text().ToUtf8String() << std::endl; | |
} | |
} |
Братски Възли
Можете да получите възела, който непосредствено предхожда или следва даден възел, като използвате съответно свойствата PreviousSibling и NextSibling. Ако възелът е последното дете на своя родител, тогава имотът NextSibling е null. И обратно, ако възелът е първото дете на своя родител, свойството PreviousSibling е null.
Следният пример за код показва как ефективно да посетите всички преки и непреки дъщерни възли на съставен възел:
For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C | |
void TraverseAllNodes(System::SharedPtr<CompositeNode> parentNode) | |
{ | |
// This is the most efficient way to loop through immediate children of a node. | |
for (System::SharedPtr<Node> childNode = parentNode->get_FirstChild(); childNode != nullptr; childNode = childNode->get_NextSibling()) | |
{ | |
// Do some useful work. | |
std::cout << Node::NodeTypeToString(childNode->get_NodeType()).ToUtf8String() << std::endl; | |
// Recurse into the node if it is a composite node. | |
if (childNode->get_IsComposite()) | |
{ | |
TraverseAllNodes(System::DynamicCast<CompositeNode>(childNode)); | |
} | |
} | |
} | |
void RecurseAllNodes(System::String const &inputDataDir) | |
{ | |
// Open a document. | |
System::SharedPtr<Document> doc = System::MakeObject<Document>(inputDataDir + u"Node.RecurseAllNodes.doc"); | |
// Invoke the recursive function that will walk the tree. | |
TraverseAllNodes(doc); | |
} |
Въведен достъп до детски и родителски възли
Досега разгледахме свойствата, които връщат един от базовите типове – Node или CompositeNode. Но понякога има ситуации, в които може да се наложи да подавате стойности към определен клас възли, като Run или Paragraph. Това означава, че не можете напълно да се измъкнете от леенето, когато работите с Aspose.Words DOM, което е съставно.
За да се намали необходимостта от леене, повечето Aspose.Words класове предоставят свойства и колекции, които осигуряват силно типиран достъп. Има три основни модела на типиран достъп:
- Родителският възел излага въведени FirstXXX и LastXXX свойства. Например Document има FirstSection и LastSection свойства. По същия начин Table има свойства като FirstRow, LastRow и други.
- Родителският възел излага набрана колекция от дъщерни възли, като Document.Sections, Body.Paragraphs и други.
- Дъщерен възел предоставя въведен достъп до своя родител, като Run.ParentParagraph, Paragraph.ParentSection и други.
Въведените свойства са просто полезни преки пътища, които понякога осигуряват по-лесен достъп от генеричните свойства, наследени от Node.ParentNode и CompositeNode.FirstChild.
Следният пример за код показва как да използвате въведени свойства за достъп до възли на дървото на документа:
For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C | |
System::SharedPtr<Document> doc = System::MakeObject<Document>(); | |
System::SharedPtr<Section> section = doc->get_FirstSection(); | |
// Quick typed access to the Body child node of the Section. | |
System::SharedPtr<Body> body = section->get_Body(); | |
// Quick typed access to all Table child nodes contained in the Body. | |
System::SharedPtr<TableCollection> tables = body->get_Tables(); | |
for (System::SharedPtr<Table> table : System::IterateOver<System::SharedPtr<Table>>(tables)) | |
{ | |
// Quick typed access to the first row of the table. | |
if (table->get_FirstRow() != nullptr) | |
{ | |
table->get_FirstRow()->Remove(); | |
} | |
// Quick typed access to the last row of the table. | |
if (table->get_LastRow() != nullptr) | |
{ | |
table->get_LastRow()->Remove(); | |
} | |
} |