Travailler avec l'arbre des nœuds du document

Travailler avec l'arbre des nœuds du document

Travailler avec l’arbre de nœuds du document

Ce guide montre comment parcourir et manipuler la structure d’un document directement via son arbre de nœuds — le modèle d’objet sur lequel Document, Section, Paragraph, Run, Table et chaque autre élément de document sont construits. Chaque élément d’un document dérive de Node, et chaque élément capable de contenir des enfants dérive de CompositeNode, de sorte que comprendre ces deux classes de base explique comment travailler avec du contenu qu’aucun assistant dédié API ne couvre déjà.


Les classes de base Node et CompositeNode

Node est la classe de base abstraite pour chaque objet dans un arbre de document. Elle expose NodeType (une valeur d’énumération identifiant le type de nœud), ParentNode (le CompositeNode englobant), Document (le document propriétaire), et PreviousSibling/NextSibling pour se déplacer parmi les nœuds au même niveau. Node.IsComposite indique si un nœud donné peut contenir des enfants. CompositeNode étend Node pour les éléments conteneurs — FirstChild, LastChild et Count décrivent ses enfants immédiats, et HasChildNodes indique s’il en existe. CompositeNode.GetChildNodes(nodeType, isDeep) récupère tous les enfants d’un NodeType donné, en recherchant éventuellement tout le sous-arbre (isDeep) plutôt que seulement les enfants directs, et CompositeNode.GetChild(nodeType, index, isDeep) récupère un seul par index.

L’énumération NodeType

NodeType répertorie chaque type de nœud que le modèle de document définit — les types structurels tels que Document, Section, Body, Paragraph, Table, Row et Cell ; les types de contenu en ligne tels que Run, Shape et Comment ; et les types de mécanisme de champ tels que FieldStart, FieldSeparator et FieldEnd, qui marquent les limites et le texte de commutation d’un champ Word dans le flux d’exécution. Fournir une valeur NodeType à GetChildNodes ou GetChild restreint la recherche aux nœuds de ce type exact, ou fournir NodeType.Any pour correspondre à tous les types de nœuds.

Parcourir et modifier l’arbre

CompositeNode.GetEnumerator() vous permet d’itérer sur les enfants directs d’un nœud, et CompositeNode implémente également SelectNodes(xpath) et SelectSingleNode(xpath) pour les requêtes basées sur XPath à travers le sous-arbre. Pour modifier l’arbre, AppendChild(newChild) et PrependChild(newChild) ajoutent un nœud au début ou à la fin des enfants, InsertBefore(newChild, refChild) et InsertAfter(newChild, refChild) insèrent par rapport à un enfant existant, et RemoveChild(oldChild) ou RemoveAllChildren() suppriment des nœuds. CompositeNode.IndexOf(child) renvoie la position d’un enfant. Sur Node lui-même, Clone(isCloneChildren) crée une copie — éventuellement profonde — et Remove() détache le nœud de son parent. Node.NextPreOrder(rootNode) et PreviousPreOrder(rootNode) parcourent l’arbre dans l’ordre du document, limité par un nœud racine donné, ce qui est une façon courante de balayer un sous-arbre entier nœud par nœud sans code récursif.

Collections de nœuds et notifications de changements

NodeCollection est une collection concrète et mutable de nœuds prenant en charge Add(node), Insert(index, node), Remove(node), RemoveAt(index), Clear(), Contains(node), IndexOf(node) et ToArray(), ainsi qu’une propriété Count. NodeList et NodeEnumerator prennent en charge l’itération de type lecture sur les résultats de requêtes, comme les nœuds renvoyés par SelectNodes. Pour observer les changements structurels au fur et à mesure qu’ils se produisent, implémentez INodeChangingCallback — ses méthodes NodeInserting(args), NodeInserted(args), NodeRemoving(args) et NodeRemoved(args) reçoivent chacune un NodeChangingArgs décrivant le Node affecté, son OldParent/NewParent, et le NodeChangingAction qui s’est produit.

Visiter les nœuds avec DocumentVisitor

Pour traiter chaque type de nœud de manière structurée sans parcourir manuellement l’arbre, sous-classez DocumentVisitor et surchargez les méthodes Visit*Start/Visit*End pour les types de nœuds qui vous intéressent — VisitParagraphStart/VisitParagraphEnd, VisitTableStart/VisitTableEnd, VisitRun, etc. — puis appelez Node.Accept(visitor) sur la racine du sous-arbre pour l’exécuter. C’est le modèle standard pour exporter, transformer ou inspecter un document sans écrire de traversée récursive personnalisée pour chaque cas d’utilisation.


Conseils et meilleures pratiques

  • Utilisez NodeType.Any avec GetChildNodes(NodeType.Any, true) lorsque vous avez besoin de chaque descendant quel que soit son type, plutôt que d’appeler GetChildNodes une fois par type.
  • Privilégiez Node.NextPreOrder(rootNode) / PreviousPreOrder(rootNode) pour un balayage plat et non récursif d’un sous-arbre plutôt que d’écrire une descente récursive manuelle.
  • Implémentez DocumentVisitor plutôt que du code de parcours d’arbre ad hoc lorsque le même traitement doit s’exécuter sur de nombreux types de nœuds différents.
  • Vérifiez Node.IsComposite avant de le convertir en CompositeNode lorsque vous travaillez avec un nœud de type inconnu.
  • Enregistrez un INodeChangingCallback lorsque vous devez réagir aux insertions ou suppressions effectuées par d’autres code (y compris les opérations intégrées), et non seulement aux modifications apportées directement par votre propre code.

Problèmes courants

ProblèmeCauseCorrection
Le transtypage d’un Node en CompositeNode génère une erreur de cast invalideLe nœud est d’un type feuille (par exemple Run ou FieldStart) qui ne peut pas contenir d’enfantsVérifiez d’abord Node.IsComposite, ou utilisez NodeType pour confirmer que le nœud est de type conteneur avant le cast
GetChildNodes ne renvoie que les enfants directsisDeep a été laissé false (ou omis lorsque la surcharge par défaut est superficielle)Passez isDeep: true pour rechercher tout le sous-arbre
Modifier une collection pendant son itération génère une erreurDes nœuds ont été ajoutés ou supprimés à l’intérieur d’un foreach sur NodeCollection ou du résultat de GetChildNodesMatérialisez d’abord les nœuds à modifier avec ToArray(), puis parcourez le tableau tout en modifiant l’arbre
Une sous-classe DocumentVisitor n’est pas appelée pour certains contenusLe visiteur a été invoqué via Accept() sur un nœud qui ne contient pas le contenu cible, ou la méthode Visit* correspondante n’a pas été surchargéeAppelez Accept() sur un ancêtre qui contient le contenu, et surchargez chaque paire Visit*Start/Visit*End pertinente aux types de nœuds traités

FAQ

Quelle est la différence entre Node et CompositeNode ?

Node est la classe de base dont dérive chaque élément de document. CompositeNode étend Node pour les éléments pouvant contenir des enfants (comme Body, Paragraph et Table); les éléments feuilles (comme Run) dérivent directement de Node et ne peuvent pas contenir d’enfants.

Comment trouver tous les nœuds d’un type spécifique dans un document?

Appelez CompositeNode.GetChildNodes(nodeType, isDeep) sur le nœud qui sert de racine à votre recherche (souvent le Document lui-même), en passant le NodeType souhaité et isDeep: true pour rechercher dans tout le sous-arbre, pas seulement les enfants directs.

Comment supprimer des nœuds en toute sécurité pendant l’itération?

Collectez d’abord les nœuds à supprimer dans un tableau — par exemple avec NodeCollection.ToArray() — puis parcourez ce tableau et appelez Remove() sur chaque nœud, au lieu de modifier la collection active pendant qu’un foreach l’itère.

Que sont les nœuds FieldStart, FieldSeparator et FieldEnd?

Ce sont des valeurs NodeType marquant la mécanique d’un champ Word intégré au flux d’exécution: FieldStart et FieldEnd délimitent le champ, et FieldSeparator sépare le code du champ de son résultat actuellement affiché.

Comment traiter chaque paragraphe, tableau et exécution dans un document?

Sous-classez DocumentVisitor, surchargez VisitParagraphStart/VisitParagraphEnd, VisitTableStart/VisitTableEnd et VisitRun pour les types de nœuds dont vous avez besoin, puis appelez Accept(visitor) sur le Document (ou toute racine de sous-arbre) pour l’exécuter.


API Reference Résumé

Classe/MéthodeDescription
NodeClasse de base abstraite pour chaque nœud d’un arbre de document
CompositeNodeClasse de base pour les nœuds pouvant contenir des enfants
CompositeNode.GetChildNodes(nodeType, isDeep)Récupérer tous les enfants d’un type donné, éventuellement dans l’ensemble du sous-arbre
CompositeNode.AppendChild(newChild) / InsertBefore(newChild, refChild)Ajouter un nœud à un conteneur à la fin, ou avant/après un enfant existant
NodeTypeEnum identifiant le type d’un nœud (Paragraph, Table, Run, FieldStart, et ainsi de suite)
NodeCollectionCollection concrète et mutable d’objets Node
Node.Clone(isCloneChildren)Copier un nœud, éventuellement en incluant ses enfants
Node.NextPreOrder(rootNode) / PreviousPreOrder(rootNode)Parcourir un sous-arbre dans l’ordre du document
INodeChangingCallbackInterface de rappel notifiée lorsque des nœuds sont insérés ou supprimés
DocumentVisitorClasse de base pour un parcours structuré, dispatché par type via Node.Accept(visitor)

Voir aussi

 Français