Come lavorare con i nodi in .NET
Questa guida mostra come percorrere, interrogare e modificare l’albero dei nodi di un documento Word direttamente in Aspose.Words FOSS per .NET, usando il Node and CompositeNode classi di base che Document, Section, Paragraph, Table, e ogni altro elemento del documento sono basati su. Copre la delimitazione di una ricerca per NodeType, aggiungendo e rimuovendo nodi programmaticamente, reagendo a cambiamenti strutturali e usando DocumentVisitor per l’attraversamento basato sul tipo.
Guida passo-passo
Passo 1: Installa il pacchetto
Aspose.Words FOSS per .NET non pubblica ancora un pacchetto NuGet – costruisci invece la libreria dal sorgente. Clona https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git, poi compila Aspose.Words.sln in configurazione Release con il SDK .NET e fai riferimento all’assembly Aspose.Words risultante dal tuo progetto. La libreria mira a .NET Standard 2.0, quindi funziona su .NET Framework 4.6.2+ e .NET 6/8/10.
Passo 2: Importa le classi richieste
Aggiungi una direttiva using Aspose.Words; – Node, CompositeNode, NodeType, NodeCollection, NodeList, INodeChangingCallback e DocumentVisitor si trovano tutti nello spazio dei nomi Aspose.Words insieme a Document.
Passo 3: Comprendere il Nodo e le Classi Base CompositeNode
Tutti gli oggetti in un albero del documento derivano dalla classe astratta Node, che espone NodeType (che identifica il tipo di nodo), ParentNode (il CompositeNode contenitore), Document (il documento proprietario) e PreviousSibling / NextSibling per spostarsi tra nodi allo stesso livello. Controlla Node.IsComposite per scoprire se un nodo dato può contenere figli prima di effettuare il cast. CompositeNode estende Node per gli elementi contenitori – FirstChild, LastChild, e Count descrivono i suoi figli immediati, e HasChildNodes segnala se ne esistono.
Passo 4: Interrogare i Figli per Tipo
Chiama CompositeNode.GetChildNodes(nodeType, isDeep) per recuperare tutti i figli di un determinato NodeType, passando isDeep: true per cercare nell’intero sottoalbero anziché solo nei figli diretti, o NodeType.Any per corrispondere a ogni tipo di nodo indipendentemente dalla categoria. CompositeNode.GetChild(nodeType, index, isDeep) recupera un singolo figlio corrispondente per indice. Per i tipi di nodo strutturali (Document, Section, Body, Paragraph, Table, Row, Cell), i tipi di contenuto in linea (Run, Shape, Comment) e i tipi di meccanismo di campo (FieldStart, FieldSeparator, FieldEnd, che segnano i confini di un campo Word e il testo di commutazione nel flusso di esecuzione), passa il valore specifico NodeType che identifica ciò che stai cercando.
Passo 5: Eseguire Query XPath su un Sottoalbero
CompositeNode implementa anche SelectNodes(xpath) e SelectSingleNode(xpath) per query basate su XPath attraverso il sottoalbero, restituendo le corrispondenze come un NodeList (o un singolo Node). CompositeNode.GetEnumerator() supporta un semplice foreach sui figli diretti di un nodo quando una query XPath è più di quanto necessario per il compito.
Passo 6: Aggiungere, Spostare e Rimuovere Nodi
Per modificare l’albero, chiama AppendChild(newChild) o PrependChild(newChild) per aggiungere un nodo all’inizio o alla fine dei figli di un contenitore, e InsertBefore(newChild, refChild) o InsertAfter(newChild, refChild) per inserire in relazione a un figlio esistente. RemoveChild(oldChild) rimuove un figlio, e RemoveAllChildren() elimina tutti i figli in una sola volta; CompositeNode.IndexOf(child) segnala la posizione di un figlio. Su Node stesso, Clone(isCloneChildren) copia un nodo – opzionalmente includendo i suoi figli – e Remove() stacca il nodo dal suo genitore.
Passo 7: Materializzare i nodi prima di modificare una collezione live
Modificare una collezione mentre un ciclo foreach la sta iterando — sia che si tratti di un NodeCollection o del risultato di GetChildNodes — genera un errore. Chiama ToArray() sulla collezione prima per materializzare i nodi in un array fisso, poi itera su quell’array chiamando Remove() o apportando altre modifiche all’albero.
Passo 8: Scansionare un sottoalbero in ordine del documento
Node.NextPreOrder(rootNode) e PreviousPreOrder(rootNode) attraversano l’albero in ordine del documento, limitati da un nodo radice specificato — un modo comune per scansionare un intero sottoalbero nodo per nodo senza scrivere codice di attraversamento ricorsivo.
Passo 9: Elaborare ogni tipo di nodo con DocumentVisitor
Per elaborare molti tipi di nodo diversi in modo strutturato, crea una sottoclasse della classe astratta DocumentVisitor e sovrascrivi i metodi Visit*Start / Visit*End per i tipi di nodo che ti interessano — ad esempio VisitParagraphStart / VisitParagraphEnd, VisitSectionStart / VisitSectionEnd, VisitBodyStart / VisitBodyEnd — poi chiama Node.Accept(visitor) sulla radice del sottoalbero per eseguirlo. Questo è lo schema standard per esportare, trasformare o ispezionare un documento senza scrivere un attraversamento ricorsivo personalizzato per ogni caso d’uso.
Passo 10: Reagire ai cambiamenti strutturali da altro codice
Implementa INodeChangingCallback quando il codice deve reagire a inserimenti o rimozioni effettuati da altro codice — incluse le operazioni integrate — non solo ai cambiamenti effettuati direttamente. I suoi metodi NodeInserting(args), NodeInserted(args), NodeRemoving(args) e NodeRemoved(args) ricevono ciascuno un NodeChangingArgs che descrive il Node interessato, il suo genitore vecchio e nuovo, e il NodeChangingAction (Insert o Remove) che si è verificato.
Problemi comuni e soluzioni
Il casting di un Node a CompositeNode genera un errore di cast non valido Il nodo è di tipo foglia – ad esempio Run or FieldStart – che non può contenere figli. Controlla Node.IsComposite prima, o usa NodeType per confermare che il nodo è di tipo contenitore prima del cast.
GetChildNodes restituisce i figli diretti quando isDeep è false isDeep è stato lasciato false (o omesso dove il sovraccarico predefinisce shallow). Passa isDeep: true to GetChildNodes() per cercare l’intero sottoalbero invece dei figli immediati.
Modificare una collezione mentre la si itera genera un errore I nodi sono stati aggiunti o rimossi all’interno di un foreach su un NodeCollection o il risultato di GetChildNodes. Chiama ToArray() prima per materializzare i nodi da modificare, quindi itera su quell’array mentre muta l’albero.
Una sottoclasse DocumentVisitor non viene chiamata per alcuni contenuti Il visitatore è stato invocato tramite Accept() su un nodo che in realtà non contiene il contenuto di destinazione, o il corrispondente Visit* metodo non è stato sovrascritto. Chiama Accept() su un antenato che contiene il contenuto, e sovrascrivi ogni Visit*Start / Visit*End coppia rilevante per i tipi di nodo in fase di elaborazione.
INodeChangingCallback non viene notificato di una modifica Il callback segnala solo le modifiche sul Document a cui è stato registrato. Conferma che il callback sia collegato al corretto Document istanza prima che la modifica avvenga, non dopo.
Domande frequenti
Qual è la differenza tra Node e CompositeNode?
Node è la classe base da cui deriva ogni elemento del documento. CompositeNode estende Node per gli elementi che possono contenere figli (come Body, Paragraph e Table); gli elementi foglia come Run derivano direttamente da Node e non possono contenere figli.
Come trovo tutti i nodi di un tipo specifico in un documento?
Chiama CompositeNode.GetChildNodes(nodeType, isDeep) sul nodo che avvia la ricerca — spesso il Document stesso — passando il NodeType di destinazione e isDeep: true per cercare l’intero sottoalbero, non solo i figli diretti.
Come rimuovo in modo sicuro i nodi durante l’iterazione?
Raccogli prima i nodi da rimuovere in un array — ad esempio con NodeCollection.ToArray() — quindi itera su quell’array e chiama Remove() su ogni nodo, invece di modificare la collezione live mentre un foreach la sta iterando.
Cosa sono i nodi FieldStart, FieldSeparator e FieldEnd?
Sono valori NodeType che segnano il meccanismo di un campo Word incorporato nel flusso di run: FieldStart e FieldEnd delimitano il campo, e FieldSeparator separa il codice del campo dal risultato attualmente visualizzato.
Come posso elaborare ogni paragrafo, tabella e run in un documento?
Sottoclassa DocumentVisitor, sovrascrivi i metodi Visit*Start / Visit*End per i tipi di nodo necessari, poi chiama Accept(visitor) sul Document (o su qualsiasi radice di sottoalbero) per eseguirlo.