Aspose.Wordsドキュメントオブジェクトモデル(DOM)

Aspose.Wordsドキュメントオブジェクトモデル(DOM)は、Word文書のメモリ内表現です。 Aspose.WordsDOMを使用すると、Word文書の内容と書式をプログラムで読み取り、操作、および変更できます。

このセクションでは、Aspose.WordsDOMの主なクラスとその関係について説明します。 Aspose.WordsDOMクラスを使用することで、文書要素と書式設定へのプログラムによるアクセスを取得できます。

ドキュメントオブジェクトツリー{#create-a-document-objects-tree}の作成

ドキュメントがAspose.WordsDOMに読み込まれると、オブジェクトツリーが構築され、ソースドキュメントの異なるタイプの要素には、さまざまなプロパティを持つ独自のDOMツリーオブジェクトがあります。

ビルドドキュメントノードツリー

Aspose.WordsがWord文書をメモリに読み込むと、さまざまな文書要素を表すさまざまな型のオブジェクトが作成されます。 テキスト、段落、表、またはセクションのすべての実行はノードであり、ドキュメント自体もノードです。 Aspose.Wordsは、すべてのドキュメントノード型のクラスを定義します。

Aspose.Wordsのドキュメントツリーは、複合デザインパターンに従います:

  • すべてのノードクラスは、最終的にAspose.Wordsドキュメントオブジェクトモデルの基本クラスであるNodeクラスから派生します。
  • SectionParagraphなどの他のノードを含むことができるノードは、CompositeNodeクラスから派生し、Nodeクラスから派生します。

下の図は、Aspose.Wordsドキュメントオブジェクトモデル(DOM)のノードクラス間の継承を示しています。 抽象クラスの名前は斜体で表示されます。

aspose-words-dom-aspose-words-cpp

例を見てみましょう。 次の画像は、さまざまな種類のコンテンツを含むMicrosoft Wordドキュメントを示しています。

document-example-aspose-words-cpp

上記のドキュメントをAspose.WordsDOMに読み込むと、以下のスキーマに示すように、オブジェクトのツリーが作成されます。

document-example-dom-aspose-words-cpp

Document, Section, Paragraph, Table, Shape, Run, また、図上の他のすべての楕円は、Word文書の要素を表すAspose.Wordsオブジェクトです。

Nodeタイプ{#get-a-node-type}を取得します

Nodeクラスは異なるノードを区別するのに十分ですが、Aspose.Wordsは特定のタイプのノードの選択など、いくつかのAPIタスクを簡素化するためにNodeType列挙を提供します。

各ノードのタイプは、NodeTypeプロパティを使用して取得できます。 このプロパティは、NodeType enumeration value. For example, a paragraph node represented by the Paragraph class returns NodeType.Paragraphと、Table class returns 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で表されているとおりに表示されます。

document-in-document-explorer-aspose-words-cpp

ドキュメントノード関係

ツリー内のノードは、それらの間の関係を持っています:

  • 別のノードを含むノードは*parent.*です
  • 親ノードに含まれるノードは、同じ親の*child.*子ノードであり、siblingノードである。
  • rootノードは常にDocumentノードです。

他のノードを含むことができるノードはCompositeNodeクラスから派生し、すべてのノードは最終的にNodeクラスから派生します。 これらの2つの基本クラスは、ツリー構造のナビゲーションと変更のための一般的なメソッドとプロパティを提供します。

次のUMLオブジェクト図は、サンプルドキュメントの複数のノードと、parent、child、およびsiblingプロパティを介した相互の関係を示しています:

document-nodes-relationships-aspose-words-cpp

ドキュメントはノード所有者です

スタイルやリストなどの重要な文書全体の構造がDocumentノードに格納されるため、ノードはツリーから作成または削除されたばかりであっても、常に特定のドキ たとえば、各段落にはドキュメントに対してグローバルに定義されたスタイルが割り当てられているため、DocumentなしでParagraphを持つことはできません。 このルールは、新しいノードを作成するときに使用されます。 新しいParagraphをDOMに直接追加するには、コンストラクタに渡されるdocumentオブジェクトが必要です。

DocumentBuilderを使用して新しい段落を作成する場合、ビルダーには常にDocumentBuilder.Documentプロパティを介してリンクされた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はnullです。:

  • ノードは作成されたばかりで、まだツリーに追加されていません。
  • ノードがツリーから削除されました。
  • これは、常にnullの親ノードを持つルート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プロパティを使用することです。CompositeNodeの子ノードにアクセスする最も効率的な方法は、FirstChildプロパティとLastChildプロパティを使用することです。 子ノードがない場合、これらのプロパティはnullを返します。

CompositeNode

ノードに子がない場合、ChildNodesプロパティは空のコレクションを返します。 HasChildNodesプロパティを使用して、CompositeNodeに子ノードが含まれているかどうかを確認できます。

次のコード例は、ChildNodesコレクションによって提供される列挙子を使用して、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 (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);
}

子ノードと親ノードへの型指定されたアクセス

これまでは、基本型の1つであるNodeまたはCompositeNodeを返すプロパティについて説明しました。 ただし、RunParagraphなどの特定のノードクラスに値をキャストする必要がある場合があります。 つまり、コンポジットであるAspose.WordsDOMを操作するときは、キャストから完全に逃れることはできません。

キャストの必要性を減らすために、ほとんどのAspose.Wordsクラスは厳密に型指定されたアクセスを提供するプロパティとコレクションを提供します。 型指定されたアクセスには3つの基本的なパターンがあります:

型指定されたプロパティは、Node.ParentNodeCompositeNode.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();
}
}