Wie man mit Knoten in .NET arbeitet

Wie man mit Knoten in .NET arbeitet

Dieser Leitfaden zeigt, wie man den Knotenbaum eines Word-Dokuments direkt in Aspose.Words FOSS für .NET, unter Verwendung der Node and CompositeNode Basisklassen, die Document, Section, Paragraph, Table, und jedes andere Dokumentelement darauf aufbauen. Es behandelt das Eingrenzen einer Suche nach NodeType, Hinzufügen und Entfernen von Knoten programmatisch, Reagieren auf strukturelle Änderungen und Verwendung von DocumentVisitor für typbasierte Traversierung.

Schritt-für-Schritt-Anleitung

Schritt 1: Paket installieren

Aspose.Words FOSS für .NET veröffentlicht noch kein NuGet-Paket – bauen Sie die Bibliothek stattdessen aus dem Quellcode. Klonen Sie https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git, dann bauen Sie Aspose.Words.sln in der Release-Konfiguration mit dem .NET-SDK und binden die resultierende Aspose.Words-Assembly in Ihr Projekt ein. Die Bibliothek zielt auf .NET Standard 2.0 ab, sodass sie auf .NET Framework 4.6.2+ und .NET 6/8/10 läuft.


Schritt 2: Erforderliche Klassen importieren

Fügen Sie eine using Aspose.Words;-Direktive hinzu – Node, CompositeNode, NodeType, NodeCollection, NodeList, INodeChangingCallback und DocumentVisitor befinden sich alle im Aspose.Words-Namespace zusammen mit Document.


Schritt 3: Verstehen Sie den Knoten und die CompositeNode Basisklassen

Jedes Objekt in einem Dokumentbaum erbt von der abstrakten Node Klasse, die NodeType (zur Identifizierung des Knotentyps), ParentNode (das umschließende CompositeNode), Document (das zugehörige Dokument) und PreviousSibling / NextSibling zum Navigieren zwischen Knoten auf derselben Ebene bereitstellt. Prüfen Sie Node.IsComposite, um herauszufinden, ob ein gegebener Knoten Kinder enthalten kann, bevor Sie ihn casten. CompositeNode erweitert Node für Containerelemente – FirstChild, LastChild und Count beschreiben seine unmittelbaren Kinder, und HasChildNodes gibt an, ob welche existieren.


Schritt 4: Kinder nach Typ abfragen

Rufen Sie CompositeNode.GetChildNodes(nodeType, isDeep) auf, um jedes Kind eines gegebenen NodeType abzurufen, wobei Sie isDeep: true übergeben, um den gesamten Unterbaum zu durchsuchen statt nur direkte Kinder, oder NodeType.Any, um jeden Knotentyp unabhängig von seiner Art zu matchen. CompositeNode.GetChild(nodeType, index, isDeep) holt ein einzelnes passendes Kind nach Index. Für strukturelle Knotentypen (Document, Section, Body, Paragraph, Table, Row, Cell), Inline-Inhaltstypen (Run, Shape, Comment) und Feld-Maschinen-Typen (FieldStart, FieldSeparator, FieldEnd, die die Grenzen eines Word-Feldes und den Umschaltttext im Laufstrom markieren), übergeben Sie den spezifischen NodeType-Wert, der angibt, wonach Sie suchen.


Schritt 5: XPath-Abfragen über einen Unterbaum ausführen

CompositeNode implementiert außerdem SelectNodes(xpath) und SelectSingleNode(xpath) für XPath-basierte Abfragen über den Unterbaum und gibt Treffer als NodeList (oder ein einzelnes Node) zurück. CompositeNode.GetEnumerator() unterstützt ein einfaches foreach über die direkten Kinder eines Knotens, wenn eine XPath-Abfrage mehr ist, als die Aufgabe erfordert.


Schritt 6: Knoten hinzufügen, verschieben und entfernen

Um den Baum zu verändern, rufen Sie AppendChild(newChild) oder PrependChild(newChild) auf, um einen Knoten am Anfang bzw. Ende der Kinder eines Containers hinzuzufügen, und InsertBefore(newChild, refChild) oder InsertAfter(newChild, refChild), um relativ zu einem vorhandenen Kind einzufügen. RemoveChild(oldChild) entfernt ein Kind, und RemoveAllChildren() löscht alle Kinder auf einmal; CompositeNode.IndexOf(child) gibt die Position eines Kindes zurück. Auf Node selbst kopiert Clone(isCloneChildren) einen Knoten – optional inklusive seiner Kinder – und Remove() löst den Knoten von seinem Elternteil.


Schritt 7: Knoten materialisieren, bevor eine Live-Sammlung geändert wird

Eine Sammlung zu modifizieren, während eine foreach-Schleife darüber iteriert – egal, ob es sich um ein NodeCollection oder das Ergebnis von GetChildNodes handelt – führt zu einem Fehler. Rufe zuerst ToArray() auf der Sammlung auf, um die Knoten in ein festes Array zu materialisieren, und iteriere dann über dieses Array, während du Remove() aufrufst oder weitere Änderungen am Baum vornimmst.


Schritt 8: Teilbaum in Dokumentreihenfolge durchsuchen

Node.NextPreOrder(rootNode) und PreviousPreOrder(rootNode) durchlaufen den Baum in Dokumentreihenfolge, begrenzt durch einen angegebenen Wurzelknoten – eine gängige Methode, einen gesamten Teilbaum Knoten für Knoten zu scannen, ohne rekursiven Traversierungscode zu schreiben.


Schritt 9: Jeden Knotentyp mit DocumentVisitor verarbeiten

Um viele verschiedene Knotentypen strukturiert zu verarbeiten, erstelle eine Unterklasse der abstrakten DocumentVisitor-Klasse und überschreibe die Visit*Start- / Visit*End-Methoden für die relevanten Knotentypen – zum Beispiel VisitParagraphStart / VisitParagraphEnd, VisitSectionStart / VisitSectionEnd, VisitBodyStart / VisitBodyEnd – rufe dann Node.Accept(visitor) auf der Wurzel des Teilbaums auf, um sie auszuführen. Dies ist das Standardmuster zum Exportieren, Transformieren oder Inspizieren eines Dokuments, ohne für jeden Anwendungsfall eigenen rekursiven Traversierungscode zu schreiben.


Schritt 10: Auf strukturelle Änderungen von anderem Code reagieren

Implementiere INodeChangingCallback, wenn Code auf Einfügungen oder Entfernungen reagieren muss, die von anderem Code durchgeführt wurden – einschließlich eingebauter Operationen – und nicht nur auf direkt vorgenommene Änderungen. Seine NodeInserting(args)-, NodeInserted(args)-, NodeRemoving(args)- und NodeRemoved(args)-Methoden erhalten jeweils ein NodeChangingArgs, das das betroffene Node, dessen alten und neuen Elternknoten sowie das aufgetretene NodeChangingAction (Insert oder Remove) beschreibt.

Häufige Probleme und Lösungen

Das Casten eines Knotens zu CompositeNode wirft einen invalid-cast error Der Knoten ist ein Blatttyp – zum Beispiel Run or FieldStart – das keine Kinder halten kann. Prüfen Node.IsComposite zuerst, oder verwenden NodeType um zu bestätigen, dass der Knoten ein Container-Typ ist, bevor er gecastet wird.

GetChildNodes gibt direkte Kinder zurück, wenn isDeep false ist isDeep wurde ausgelassen false (oder weggelassen, wenn die Überladung standardmäßig flach ist). Übergeben isDeep: true to GetChildNodes() um den gesamten Unterbaum zu durchsuchen, anstatt unmittelbarer Kinder.

Das Ändern einer Sammlung während der Iteration wirft einen Fehler Knoten wurden innerhalb eines foreach über ein NodeCollection oder das Ergebnis von GetChildNodes. Aufrufen ToArray() zuerst, um die zu ändernden Knoten zu materialisieren, dann über dieses Array iterieren, während der Baum mutiert wird.

Eine DocumentVisitor-Unterklasse wird für einige Inhalte nicht aufgerufen Der Besucher wurde aufgerufen über Accept() auf einem Knoten, der den Zielinhalt tatsächlich nicht enthält, oder der entsprechende Visit* Methode wurde nicht überschrieben. Aufrufen Accept() auf einem übergeordneten Knoten, der den Inhalt enthält, und überschreiben Sie jede Visit*Start / Visit*End Paar, das für die verarbeiteten Knotentypen relevant ist.

INodeChangingCallback wird über eine Änderung nicht benachrichtigt Der Callback meldet Änderungen nur an dem Document gegenüber dem es registriert wurde. Bestätigen Sie, dass der Callback an das richtige Document Instanz bevor die Änderung eintritt, nicht danach.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Node und CompositeNode?

Node ist die Basisklasse, von der jedes Dokumentelement abgeleitet wird. CompositeNode erweitert Node für Elemente, die Kinder enthalten können (wie Body, Paragraph und Table); Blatt-Elemente wie Run erben direkt von Node und können keine Kinder enthalten.

Wie finde ich alle nodes eines bestimmten Typs in einem Dokument?

Rufe CompositeNode.GetChildNodes(nodeType, isDeep) auf dem Node auf, der die Suche wurzelt – oft das Document selbst – und übergebe das Ziel-NodeType und isDeep: true, um den gesamten Unterbaum zu durchsuchen, nicht nur direkte Kinder.

Wie entferne ich nodes sicher während der Iteration?

Sammle die zu entfernenden nodes zuerst in ein Array – zum Beispiel mit NodeCollection.ToArray() –, iteriere dann über dieses Array und rufe Remove() für jeden Node auf, anstatt die Live-Collection zu verändern, während ein foreach sie iteriert.

Was sind FieldStart, FieldSeparator und FieldEnd nodes?

Sie sind NodeType-Werte, die die Mechanik eines in den Laufstrom eingebetteten Word-Feldes kennzeichnen: FieldStart und FieldEnd binden das Feld, und FieldSeparator trennt den Code des Feldes von seinem derzeit angezeigten Ergebnis.

Wie verarbeite ich jeden Absatz, jede Tabelle und jeden Run in einem Dokument?

Unterklasse DocumentVisitor, überschreibe die Visit*Start / Visit*End Methoden für die benötigten Knotentypen, dann rufe Accept(visitor) auf dem Document (oder irgendeinem Unterbaum-Wurzel) auf, um es auszuführen.

Siehe auch

 Deutsch