Werken met de Document Node Tree

Werken met de Document Node Tree

Werken met de Documentknooppuntboom

Deze gids laat zien hoe je door de structuur van een document navigeert en deze bewerkt, rechtstreeks via de knooppuntboom — het objectmodel waarop Document, Section, Paragraph, Run, Table en elk ander documentelement zijn gebaseerd. Elk element in een document is afgeleid van Node, en elk element dat kinderen kan bevatten is afgeleid van CompositeNode, dus het begrijpen van deze twee basisklassen verklaart hoe je met inhoud werkt die nog niet door een toegewijde helper API wordt gedekt.


De Node- en CompositeNode basisklassen

Node is de abstracte basisklasse voor elk object in een documentboom. Het biedt NodeType (een enum-waarde die aangeeft welk type knooppunt dit is), ParentNode (de omsluitende CompositeNode), Document (het eigenaar-document), en PreviousSibling/NextSibling om over knooppunten op hetzelfde niveau te navigeren. Node.IsComposite geeft aan of een bepaald knooppunt kinderen kan bevatten. CompositeNode breidt Node uit voor container-elementen — FirstChild, LastChild en Count beschrijven de directe kinderen, en HasChildNodes geeft aan of er überhaupt kinderen bestaan. CompositeNode.GetChildNodes(nodeType, isDeep) haalt alle kinderen op van een gegeven NodeType, eventueel door de volledige subboom (isDeep) te doorzoeken in plaats van alleen directe kinderen, en CompositeNode.GetChild(nodeType, index, isDeep) haalt er één op op basis van index.

De NodeType Enum

NodeType somt elk type knooppunt op dat het documentmodel definieert — structurele typen zoals Document, Section, Body, Paragraph, Table, Row en Cell; inline-inhoudstypen zoals Run, Shape en Comment; en veld-machinetoepassingen zoals FieldStart, FieldSeparator en FieldEnd, die de grenzen en schakeltekst van een Word-veld binnen de run-stroom markeren. Het doorgeven van een NodeType-waarde aan GetChildNodes of GetChild beperkt de zoekopdracht tot knooppunten van precies dat type, of geef NodeType.Any op om elk knooppunttype te matchen.

Traverseren en wijzigen van de boom

CompositeNode.GetEnumerator() stelt je in staat om over de directe kinderen van een knoop te itereren, en CompositeNode implementeert ook SelectNodes(xpath) en SelectSingleNode(xpath) voor XPath-gebaseerde query’s over de subboom. Om de boom te wijzigen, voegen AppendChild(newChild) en PrependChild(newChild) een knoop toe aan het begin of einde van de kinderen, InsertBefore(newChild, refChild) en InsertAfter(newChild, refChild) voegen in relatief tot een bestaand kind in, en RemoveChild(oldChild) of RemoveAllChildren() verwijderen knopen. CompositeNode.IndexOf(child) geeft de positie van een kind terug. Op Node zelf maakt Clone(isCloneChildren) een kopie — eventueel diepgaand — en Remove() ontkoppelt de knoop van zijn ouder. Node.NextPreOrder(rootNode) en PreviousPreOrder(rootNode) lopen door de boom in documentvolgorde, begrensd door een opgegeven wortelknoop, wat een gebruikelijke manier is om een volledige subboom knoop-voor-knoop te scannen zonder recursieve code.

Node-collecties en wijzigingsmeldingen

NodeCollection is een concrete, mutabele verzameling knopen die Add(node), Insert(index, node), Remove(node), RemoveAt(index), Clear(), Contains(node), IndexOf(node) en ToArray() ondersteunt, naast een Count eigenschap. NodeList en NodeEnumerator ondersteunen iteratie in leesstijl over query-resultaten, zoals de knopen die worden geretourneerd door SelectNodes. Om structurele wijzigingen in realtime te observeren, implementeer INodeChangingCallback — de NodeInserting(args), NodeInserted(args), NodeRemoving(args) en NodeRemoved(args) methoden ontvangen elk een NodeChangingArgs die de getroffen Node, zijn OldParent/NewParent, en de NodeChangingAction beschrijft die plaatsvond.

Bezoeken van knopen met DocumentVisitor

Voor het verwerken van elk knoopt type op een gestructureerde manier zonder handmatig door de boom te wandelen, maak een subclass van DocumentVisitor en overschrijf de Visit*Start/Visit*End methoden voor de knooptypes waarin je geïnteresseerd bent — VisitParagraphStart/VisitParagraphEnd, VisitTableStart/VisitTableEnd, VisitRun, enzovoort — roep vervolgens Node.Accept(visitor) aan op de wortel van de subboom om het uit te voeren. Dit is het standaardpatroon voor het exporteren, transformeren of inspecteren van een document zonder aangepaste recursieve traversals voor elk gebruiksgeval.


Tips en best practices

  • Gebruik NodeType.Any met GetChildNodes(NodeType.Any, true) wanneer je elke afstammeling nodig hebt ongeacht het type, in plaats van GetChildNodes één keer per type aan te roepen.
  • Geef de voorkeur aan Node.NextPreOrder(rootNode) / PreviousPreOrder(rootNode) voor een platte, niet-recursieve scan van een subboom in plaats van handmatige recursieve afdaling te schrijven.
  • Implementeer DocumentVisitor in plaats van ad-hoc boomdoorloopcode wanneer dezelfde verwerking moet worden uitgevoerd op veel verschillende knooptypen.
  • Controleer Node.IsComposite voordat je cast naar CompositeNode bij het werken met een knoop van onbekend type.
  • Registreer een INodeChangingCallback wanneer je moet reageren op invoegingen of verwijderingen die door andere code (inclusief ingebouwde bewerkingen) worden uitgevoerd, en niet alleen op wijzigingen die jouw eigen code rechtstreeks maakt.

Veelvoorkomende problemen

ProbleemOorzaakOplossing
Het casten van een Node naar CompositeNode gooit een invalid-cast foutHet knooppunt is een bladtype (bijvoorbeeld Run of FieldStart) dat geen kinderen kan bevattenControleer eerst Node.IsComposite, of gebruik NodeType om te bevestigen dat het knooppunt een containertype is vóór het casten
GetChildNodes retourneert alleen directe kinderenisDeep werd false gelaten (of weggelaten waar de overload standaard shallow is)Geef isDeep: true door om de hele subboom te doorzoeken
Een collectie wijzigen tijdens het itereren erover veroorzaakt een foutKnooppunten werden toegevoegd of verwijderd binnen een foreach over NodeCollection of het resultaat van GetChildNodesMaterialiseer eerst de knooppunten die moeten worden aangepast met ToArray(), en loop vervolgens door de array terwijl je de boom wijzigt
Een DocumentVisitor-subklasse wordt niet aangeroepen voor bepaalde inhoudDe visitor werd aangeroepen via Accept() op een knooppunt dat de doelinhoud niet bevat, of de overeenkomstige Visit*-methode werd niet overschrevenRoep Accept() aan op een ouder die de inhoud bevat, en overschrijf elk Visit*Start/Visit*End-paar dat relevant is voor de verwerkte knooppunttypes

FAQ

Wat is het verschil tussen Node en CompositeNode?

Node is de basisklasse waar elk documentelement van afstamt. CompositeNode breidt Node uit voor elementen die kinderen kunnen bevatten (zoals Body, Paragraph en Table); blad-elementen (zoals Run) erven rechtstreeks van Node en kunnen geen kinderen bevatten.

Hoe vind ik alle knopen van een specifiek type in een document?

Roep CompositeNode.GetChildNodes(nodeType, isDeep) aan op het knooppunt dat je zoekopdracht wortelt (vaak de Document zelf), waarbij je de NodeType doorgeeft die je wilt en isDeep: true om de hele subboom te doorzoeken, niet alleen de directe kinderen.

Hoe kan ik knooppunten veilig verwijderen tijdens het itereren?

Verzamel eerst de te verwijderen knooppunten in een array — bijvoorbeeld met NodeCollection.ToArray() — en iterateer vervolgens over die array en roep Remove() aan op elk knooppunt, in plaats van de live-collectie te wijzigen terwijl een foreach erdoor iterereert.

Wat zijn FieldStart, FieldSeparator en FieldEnd knooppunten?

Het zijn NodeType waarden die de mechaniek van een Word-veld markeren dat in de run-stroom is ingebed: FieldStart en FieldEnd binden het veld, en FieldSeparator scheidt de code van het veld van het momenteel weergegeven resultaat.

Hoe verwerk ik elke alinea, tabel en run in een document?

Subklasseer DocumentVisitor, overschrijf VisitParagraphStart/VisitParagraphEnd, VisitTableStart/VisitTableEnd en VisitRun voor de knooppunttypes die je nodig hebt, roep vervolgens Accept(visitor) aan op de Document (of enige subboom-wortel) om het uit te voeren.


API Reference Samenvatting

Klasse/MethodeBeschrijving
NodeAbstracte basisklasse voor elke node in een documentboom
CompositeNodeBasisklasse voor nodes die kinderen kunnen bevatten
CompositeNode.GetChildNodes(nodeType, isDeep)Haal alle kinderen van een gegeven type op, optioneel over de gehele subboom
CompositeNode.AppendChild(newChild) / InsertBefore(newChild, refChild)Voeg een node toe aan een container aan het einde, of vóór/na een bestaand kind
NodeTypeEnum die het type van een knoop identificeert (Paragraph, Table, Run, FieldStart, enzovoort)
NodeCollectionConcreet, wijzigbare collectie van Node objecten
Node.Clone(isCloneChildren)Kopieer een knoop, optioneel inclusief de kinderen
Node.NextPreOrder(rootNode) / PreviousPreOrder(rootNode)Doorloop een subboom in documentvolgorde
INodeChangingCallbackCallback interface die wordt geïnformeerd wanneer knooppunten worden ingevoegd of verwijderd
DocumentVisitorBasisklasse voor gestructureerde, type-gestuurde traversie via Node.Accept(visitor)

Zie ook

 Nederlands