.NET でノードを操作する方法
このガイドでは、Word ドキュメントのノードツリーを直接操作し、歩き回り、クエリし、変更する方法を示します Aspose.Words の .NET 用 FOSS、以下を使用して Node and CompositeNode ベースクラスは Document, Section, Paragraph, Table、他のすべてのドキュメント要素が構築される基盤です。検索のスコープ指定について説明します NodeType、ノードをプログラムで追加・削除し、構造的変更に応答し、そして使用する DocumentVisitor 型ディスパッチトラバーサルのために。
ステップバイステップガイド
ステップ 1: パッケージをインストールする
Aspose.Words FOSS for .NET はまだ NuGet パッケージを公開していません — 代わりにソースからライブラリをビルドしてください。https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git をクローンし、.NET SDK を使用して Release 構成で Aspose.Words.sln をビルドし、生成された Aspose.Words アセンブリをプロジェクトから参照します。このライブラリは .NET Standard 2.0 を対象としているため、.NET Framework 4.6.2+ および .NET 6/8/10 上で動作します。
ステップ 2: 必要なクラスをインポートする
using Aspose.Words; ディレクティブを追加します — Node、CompositeNode、NodeType、NodeCollection、NodeList、INodeChangingCallback、DocumentVisitor はすべて Aspose.Words 名前空間にあり、Document と共に存在します。
ステップ 3: ノードと CompositeNode 基底クラスを理解する
文書ツリー内のすべてのオブジェクトは抽象的な Node クラスから派生し、このクラスは NodeType(ノードの種類を識別)、ParentNode(囲んでいる CompositeNode)、Document(所有ドキュメント)、および同レベルのノード間の移動用に PreviousSibling / NextSibling を公開します。キャストする前に、対象ノードが子を保持できるかどうかは Node.IsComposite を確認してください。CompositeNode はコンテナ要素用に Node を拡張し、FirstChild、LastChild、Count が直接の子を記述し、HasChildNodes が子の有無を報告します。
ステップ 4: 種類で子ノードをクエリする
指定された NodeType のすべての子を取得するには CompositeNode.GetChildNodes(nodeType, isDeep) を呼び出し、直接の子だけでなくサブツリー全体を検索したい場合は isDeep: true を、種類に関係なくすべてのノードタイプにマッチさせたい場合は NodeType.Any を渡します。CompositeNode.GetChild(nodeType, index, isDeep) はインデックスで一致する子をひとつ取得します。構造ノードタイプ(Document、Section、Body、Paragraph、Table、Row、Cell)、インラインコンテンツタイプ(Run、Shape、Comment)、およびフィールド機構タイプ(FieldStart、FieldSeparator、FieldEnd、これらは Word フィールドの境界とランストリーム内のスイッチテキストを示す)については、探しているものを識別する特定の NodeType 値を渡してください。
ステップ 5: サブツリー全体で XPath クエリを実行する
CompositeNode はサブツリー全体で XPath ベースのクエリを行うための SelectNodes(xpath) と SelectSingleNode(xpath) も実装しており、一致結果を NodeList(または単一の Node)として返します。XPath クエリが必要以上に複雑な場合、CompositeNode.GetEnumerator() はノードの直接の子に対するシンプルな foreach をサポートします。
ステップ 6: ノードの追加、移動、削除
ツリーを変更するには、コンテナの子の先頭または末尾にノードを追加するために AppendChild(newChild) または PrependChild(newChild) を呼び出し、既存の子に対して相対的に挿入するには InsertBefore(newChild, refChild) または InsertAfter(newChild, refChild) を使用します。RemoveChild(oldChild) は子をひとつ削除し、RemoveAllChildren() はすべての子を一度にクリアします;CompositeNode.IndexOf(child) は子の位置を報告します。Node 自体については、Clone(isCloneChildren) がノードをコピーします(オプションで子ノードも含められます)し、Remove() がノードを親から切り離します。
ステップ7: ライブコレクションを変更する前にノードを具象化する
コレクションを foreach ループが反復している間に変更すると、NodeCollection であろうと GetChildNodes の結果であろうとエラーが発生します。まずコレクションに対して ToArray() を呼び出してノードを固定配列に具象化し、その配列を反復しながら Remove() を呼び出すか、ツリーに他の変更を加えてください。
ステップ8: ドキュメント順でサブツリーを走査する
Node.NextPreOrder(rootNode) と PreviousPreOrder(rootNode) は、指定されたルートノードで範囲を限定し、ドキュメント順でツリーをステップします――再帰的な走査コードを書かずにサブツリー全体をノード単位で走査する一般的な方法です。
ステップ9: DocumentVisitor を使用してすべてのノードタイプを処理する
多くの異なるノードタイプを体系的に処理するには、抽象 DocumentVisitor クラスをサブクラス化し、重要なノードタイプに対して Visit*Start / Visit*End メソッドをオーバーライドします――例えば VisitParagraphStart / VisitParagraphEnd、VisitSectionStart / VisitSectionEnd、VisitBodyStart / VisitBodyEnd など――そしてサブツリーのルートで Node.Accept(visitor) を呼び出して実行します。これは、各ユースケースごとにカスタムの再帰走査を書かずに、ドキュメントのエクスポート、変換、または検査を行う標準的なパターンです。
ステップ10: 他のコードからの構造変更に反応する
コードが他のコード(組み込み操作を含む)によって行われた挿入や削除、直接的な変更だけでなく、構造的な変更に反応する必要がある場合は INodeChangingCallback を実装します。その NodeInserting(args)、NodeInserted(args)、NodeRemoving(args)、および NodeRemoved(args) メソッドはそれぞれ、影響を受けた Node を記述した NodeChangingArgs を受け取り、古い親と新しい親、そして発生した NodeChangingAction(Insert または Remove)を提供します。
一般的な問題と対策
Node を CompositeNode にキャストすると、invalid-cast エラーがスローされます ノードはリーフタイプです – たとえば Run or FieldStart – 子を保持できません。確認してください Node.IsComposite 最初に、または使用してください NodeType キャストする前に、ノードがコンテナタイプであることを確認してください。
GetChildNodes は isDeep が false のとき直接の子要素を返します isDeep 残されました false (またはオーバーロードが浅いデフォルトの場合は省略)。渡す isDeep: true to GetChildNodes() 直接の子ではなく、サブツリー全体を検索します。
コレクションを反復処理中に変更するとエラーがスローされます ノードが a の内部で追加または削除されました foreach a の上で NodeCollection またはその結果 GetChildNodes。 Call ToArray() 最初に変更するノードを具体化し、次にツリーを変更しながらその配列を反復処理します。
ある DocumentVisitor サブクラスが一部のコンテンツで呼び出されません ビジターは via によって呼び出されました Accept() 実際に対象コンテンツを含んでいないノード上、または対応する Visit* メソッドがオーバーライドされていませんでした。呼び出す Accept() コンテンツを含む先祖ノード上で、そしてすべての Visit*Start / Visit*End 処理中のノードタイプに関連するペアを.
INodeChangingCallback は変更について通知されません コールバックは、対象上の変更のみを報告します Document それが登録された対象です。コールバックが正しい Document インスタンスに変更が発生する前にアタッチされていることを確認してください、後ではなく。
よくある質問
Node と CompositeNode の違いは何ですか?
Node はすべての文書要素が派生する基底クラスです。CompositeNode は子要素を持てる要素(例:Body、Paragraph、Table)のために Node を拡張します;Run のようなリーフ要素は Node から直接派生し、子要素を保持できません。
特定のタイプのすべてのノードを文書内で見つけるにはどうすればよいですか?
検索のルートとなるノード(多くの場合は Document 自体)に対して CompositeNode.GetChildNodes(nodeType, isDeep) を呼び出し、対象の NodeType と isDeep: true を渡して、直接の子だけでなくサブツリー全体を検索します。
イテレーション中にノードを安全に削除するにはどうすればよいですか?
まず削除するノードを配列に集めます(例:NodeCollection.ToArray() を使用)。その配列をイテレートし、各ノードに対して Remove() を呼び出します。foreach がイテレートしている間にライブコレクションを変更しないようにします。
FieldStart、FieldSeparator、および FieldEnd ノードとは何ですか?
それらは、実行ストリームに埋め込まれた Word フィールドの機構を示す NodeType 値です:FieldStart と FieldEnd がフィールドをバインドし、FieldSeparator がフィールドのコードと現在表示されている結果を分割します。
ドキュメント内のすべての段落、表、および run を処理するにはどうすればよいですか?
必要なノードタイプに対して Visit*Start / Visit*End メソッドをオーバーライドし、DocumentVisitor をサブクラス化して、Accept(visitor) を Document(または任意のサブツリールート)に対して呼び出して実行します。