Aspose.Words Document Object Model (DOM)

Aspose.Words Document Object Model (DOM) は、Word ドキュメントのメモリ内表現です。 Aspose.Words DOM を使用すると、Word ドキュメントのコンテンツと書式設定をプログラムで読み取り、操作、変更できます。

このセクションでは、Aspose.Words DOM の主要なクラスとそれらの関係について説明します。 Aspose.Words DOM クラスを使用すると、ドキュメント要素と書式設定にプログラムからアクセスできます。

Document オブジェクト ツリー {#create-a-document-objects-tree} の作成

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

ドキュメント ノード ツリーの構築

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

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

  • すべてのノード クラスは、最終的には Aspose.Words Document Object Model の基本クラスである Node クラスから派生します。
  • SectionParagraph など、他のノードを含むことができるノードは CompositeNode クラスから派生し、CompositeNode クラスは Node クラスから派生します。

以下の図は、Aspose.Words Document Object Model (DOM) のノード クラス間の継承を示しています。抽象クラスの名前は斜体で表示されます。

アスポーズワードダム

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

文書例-aspose-words

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

ドム・アスポーズ・ワード

DocumentSectionParagraphTableShapeRun、および図上のその他すべての省略記号は、Word 文書の要素を表す Aspose.Words オブジェクトです。

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

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

各ノードのタイプは、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;

ドキュメント ツリー ナビゲーション

Aspose.Words はドキュメントをノード ツリーとして表現し、ノード間を移動できるようにします。このセクションでは、Aspose.Words でドキュメント ツリーを探索および移動する方法について説明します。

前に示したサンプル ドキュメントをドキュメント エクスプローラーで開くと、ノード ツリーが Aspose.Words で表現されているとおりに表示されます。

ドキュメントインドキュメントエクスプローラー

ドキュメントノードの関係

ツリー内のノード間には次のような関係があります。

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

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

次の UML オブジェクト図は、サンプル ドキュメントのいくつかのノードと、親、子、兄弟プロパティを介したそれらの相互関係を示しています。

ドキュメントノード関係-aspose-words

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

スタイルやリストなどの重要なドキュメント全体の構造が Document ノードに格納されるため、ノードは常に特定のドキュメントに属します。これは、ノードが作成されたばかりか、ツリーから削除されたばかりであってもです。たとえば、各段落にはドキュメントに対してグローバルに定義されたスタイルが割り当てられているため、Document なしで Paragraph を作成することはできません。このルールは、新しいノードを作成するときに使用されます。新しい 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 は null です。

  • ノードは作成されたばかりで、まだツリーに追加されていません。
  • ノードがツリーから削除されました。
  • これは、常にヌルの親ノードを持つルート Document ノードです。

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 プロパティはノードのライブ コレクションです。つまり、ノードの削除または追加など、ドキュメントが変更されるたびに、ChildNodes コレクションが自動的に更新されます。

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

次のコード例は、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);
}
}

子ノードおよび親ノードへの型付きアクセス

これまで、基本タイプの 1 つである Node または CompositeNode を返すプロパティについて説明してきました。ただし、場合によっては、RunParagraph などの特定のノード クラスに値をキャストする必要がある場合があります。つまり、複合である Aspose.Words DOM を使用する場合、キャストから完全に逃れることはできません。

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

型付きプロパティは単なる便利なショートカットであり、Node.ParentNodeCompositeNode.FirstChild から継承された汎用プロパティよりも簡単にアクセスできる場合があります。

次のコード例は、型付きプロパティを使用してドキュメント ツリーのノードにアクセスする方法を示しています。

// 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();
}