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

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

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

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

文書がAspose.WordsDOMに読み込まれると、オブジェクトツリーが構築され、ソース文書の異なるタイプの要素には、さまざまなプロパティを持つ独自のDOMtreeオブジェク

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

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

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

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

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

aspose-words-dom

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

document-example

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

document-example-dom

Document, Section, Paragraph, Table, Shape, Run, また、図上の他のすべての楕円は、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-Java
Document doc = new Document();
// Returns NodeType.Document
int type = doc.getNodeType();

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

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

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

document-in-document-explorer

ドキュメントノード関係

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

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

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

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

document-nodes-relationships

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

スタイルやリストなどの重要な文書全体の構造が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-Java
// 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.
System.out.println("Paragraph has no parent node: " + (para.getParentNode() == null));
// But the paragraph node knows its document.
System.out.println("Both nodes' documents are the same: " + (para.getDocument() == 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.getParagraphFormat().setStyleName("Heading 1");
// Now add the paragraph to the main text of the first section.
doc.getFirstSection().getBody().appendChild(para);
// The paragraph node is now a child of the Body node.
System.out.println("Paragraph has a parent node: " + (para.getParentNode() != null));

親ノード

各ノードにはParentNodeプロパティで指定された親があります。 次の場合、ノードには親ノードがありません。ParentNodeはnullです。:

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

ノードを親から削除するには、Removeメソッドを呼び出します。次のコード例は、親ノードにアクセスする方法を示しています:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
// 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.getFirstChild();
// The section's parent node is the document.
System.out.println("Section parent is the document: " + (doc == section.getParentNode()));

子ノード

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-Java
Document doc = new Document(dataDir + "Document.doc");
Paragraph paragraph = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 0, true);
NodeCollection children = paragraph.getChildNodes();
for (Node child : (Iterable<Node>) children) {
// Paragraph may contain children of various types such as runs, shapes and so on.
if (child.getNodeType() == NodeType.RUN) {
// Say we found the node that we want, do something useful.
Run run = (Run) child;
System.out.println(run.getText());
}
}

次のコード例は、インデックス付きアクセスを使用してCompositeNodeの直接の子ノードを列挙する方法を示しています:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
Document doc = new Document(dataDir + "Document.doc");
Paragraph paragraph = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 0, true);
NodeCollection children = paragraph.getChildNodes();
for (int i = 0; i < children.getCount(); i++) {
Node child = children.get(i);
// Paragraph may contain children of various types such as runs, shapes and so on.
if (child.getNodeType() == NodeType.RUN) {
// Say we found the node that we want, do something useful.
Run run = (Run) child;
System.out.println(run.getText());
}
}

兄弟ノード

それぞれPreviousSiblingプロパティとNextSiblingプロパティを使用して、特定のノードの直前または後続のノードを取得できます。 ノードがその親の最後の子である場合、NextSiblingプロパティはnullです。 逆に、ノードがその親の最初の子である場合、PreviousSiblingプロパティはnullです。

次のコード例は、複合ノードのすべての直接および間接の子ノードを効率的に訪問する方法を示しています:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
public static void main(String[] args) throws Exception {
String dataDir = Utils.getSharedDataDir(ChildNodes.class) + "DocumentObjectModel/";
recurseAllNodes(dataDir);
}
public static void recurseAllNodes(String dataDir) throws Exception {
// Open a document
Document doc = new Document(dataDir + "Node.RecurseAllNodes.doc");
// Invoke the recursive function that will walk the tree.
traverseAllNodes(doc);
}
/**
* A simple function that will walk through all children of a specified node
* recursively and print the type of each node to the screen.
*/
public static void traverseAllNodes(CompositeNode parentNode) throws Exception {
// This is the most efficient way to loop through immediate children of a node.
for (Node childNode = parentNode.getFirstChild(); childNode != null; childNode = childNode.getNextSibling()) {
// Do some useful work.
System.out.println(Node.nodeTypeToString(childNode.getNodeType()));
// Recurse into the node if it is a composite node.
if (childNode.isComposite())
traverseAllNodes((CompositeNode) childNode);
}
}

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

これまでは、基本型の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-Java
Document doc = new Document();
// Quick typed access to the first child Section node of the Document.
Section section = doc.getFirstSection();
// Quick typed access to the Body child node of the Section.
Body body = section.getBody();
// Quick typed access to all Table child nodes contained in the Body.
TableCollection tables = body.getTables();
for (Table table : tables) {
// Quick typed access to the first row of the table.
if (table.getFirstRow() != null)
table.getFirstRow().remove();
// Quick typed access to the last row of the table.
if (table.getLastRow() != null)
table.getLastRow().remove();
}