Hur man arbetar med noder i .NET

Hur man arbetar med noder i .NET

Den här guiden visar hur man traverserar, söker och ändrar ett Word-dokuments nodträd direkt i Aspose.Words FOSS för .NET, med Node and CompositeNode bas-klasser som Document, Section, Paragraph, Table, och varje annat dokumentelement bygger på. Den täcker avgränsning av en sökning genom NodeType, lägga till och ta bort noder programmatiskt, reagera på strukturella förändringar, och använda DocumentVisitor för typ-dispatchet traversering.

Steg-för-steg-guide

Steg 1: Installera paketet

Aspose.Words FOSS för .NET har ännu inte publicerat ett NuGet-paket – bygg biblioteket från källkoden istället. Klona https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git, bygg sedan Aspose.Words.sln i Release-konfiguration med .NET-SDK:n och referera den resulterande Aspose.Words-assemblyn från ditt projekt. Biblioteket riktar sig mot .NET Standard 2.0, så det körs på .NET Framework 4.6.2+ och .NET 6/8/10.


Steg 2: Importera nödvändiga klasser

Lägg till en using Aspose.Words;-direktiv – Node, CompositeNode, NodeType, NodeCollection, NodeList, INodeChangingCallback och DocumentVisitor finns alla i Aspose.Words-namnutrymmet tillsammans med Document.


Steg 3: Förstå noden och CompositeNode basklasser

Varje objekt i ett dokumentträd ärver från den abstrakta Node klassen, som exponerar NodeType (identifierar vilken typ av nod det är), ParentNode (det omgivande CompositeNode), Document (det ägande dokumentet), och PreviousSibling / NextSibling för att navigera mellan noder på samma nivå. Kontrollera Node.IsComposite för att ta reda på om en given nod kan innehålla barn innan du kastar den. CompositeNode utökar Node för behållarelement – FirstChild, LastChild och Count beskriver dess omedelbara barn, och HasChildNodes rapporterar om några finns.


Steg 4: Fråga barn efter typ

Anropa CompositeNode.GetChildNodes(nodeType, isDeep) för att hämta varje barn till en given NodeType, skicka med isDeep: true för att söka i hela underträdet istället för bara direkta barn, eller NodeType.Any för att matcha varje nodtyp oavsett sort. CompositeNode.GetChild(nodeType, index, isDeep) hämtar ett enstaka matchande barn efter index. För strukturella nodtyper (Document, Section, Body, Paragraph, Table, Row, Cell), inline-innehållstyper (Run, Shape, Comment), och fältmaskintyper (FieldStart, FieldSeparator, FieldEnd, som markerar ett Word-fälts gränser och växlar text i körströmmen), skicka det specifika NodeType-värdet som identifierar vad du söker.


Steg 5: Kör XPath-frågor över ett underträd

CompositeNode implementerar även SelectNodes(xpath) och SelectSingleNode(xpath) för XPath-baserade frågor över underträdet, och returnerar träffar som en NodeList (eller en enskild Node). CompositeNode.GetEnumerator() stödjer en enkel foreach över en nods direkta barn när en XPath-fråga är mer än vad uppgiften kräver.


Steg 6: Lägg till, flytta och ta bort noder

För att modifiera trädet, anropa AppendChild(newChild) eller PrependChild(newChild) för att lägga till en nod i början eller slutet av en behållares barn, och InsertBefore(newChild, refChild) eller InsertAfter(newChild, refChild) för att infoga relativt till ett befintligt barn. RemoveChild(oldChild) tar bort ett barn, och RemoveAllChildren() rensar alla barn på en gång; CompositeNode.IndexOf(child) rapporterar ett barns position. På Node själv, Clone(isCloneChildren) kopierar en nod – eventuellt inklusive dess barn – och Remove() kopplar loss noden från dess förälder.


Steg 7: Materialisera noder innan du muterar en levande samling

Att ändra en samling medan en foreach-loop itererar över den – oavsett om det är en NodeCollection eller resultatet av GetChildNodes – kastar ett fel. Anropa ToArray() på samlingen först för att materialisera noderna till en fast array, och iterera sedan över den arrayen medan du anropar Remove() eller gör andra ändringar i trädet.


Steg 8: Skanna ett underträd i dokumentordning

Node.NextPreOrder(rootNode) och PreviousPreOrder(rootNode) går igenom trädet i dokumentordning, begränsat av en given rotnod – ett vanligt sätt att skanna ett helt underträd nod för nod utan att skriva rekursiv traversalkod.


Steg 9: Bearbeta varje nodtyp med DocumentVisitor

För att bearbeta många olika nodtyper på ett strukturerat sätt, subklassa den abstrakta DocumentVisitor-klassen och åsidosätt Visit*Start/Visit*End-metoderna för de nodtyper som är relevanta – till exempel VisitParagraphStart/VisitParagraphEnd, VisitSectionStart/VisitSectionEnd, VisitBodyStart/VisitBodyEnd – och anropa sedan Node.Accept(visitor) på roten av underträdet för att köra den. Detta är det vanliga mönstret för att exportera, transformera eller inspektera ett dokument utan att skriva anpassad rekursiv traversering för varje användningsfall.


Steg 10: Reagera på strukturella förändringar från annan kod

Implementera INodeChangingCallback när kod behöver reagera på insättningar eller borttagningar som gjorts av annan kod – inklusive inbyggda operationer – inte bara förändringar som gjorts direkt. Dess NodeInserting(args), NodeInserted(args), NodeRemoving(args) och NodeRemoved(args)-metoder får var för sig ett NodeChangingArgs som beskriver den berörda Node, dess gamla och nya förälder, samt den NodeChangingAction (Insert eller Remove) som inträffade.

Vanliga problem och lösningar

Att kasta en Node till CompositeNode kastar ett ogiltigt typ-kastfel Noden är av lövtyp – till exempel Run or FieldStart – som inte kan ha barn. Kontrollera Node.IsComposite först, eller använd NodeType för att bekräfta att noden är av containertyp innan du kastar.

GetChildNodes returnerar direkta barn när isDeep är falskt isDeep lämnades false (eller utelämnad där överlagringen standardar till ytlig). Skicka isDeep: true to GetChildNodes() för att söka i hela underträdet istället för omedelbara barn.

Att modifiera en samling medan du itererar över den kastar ett fel Noder lades till eller togs bort inuti en foreach över en NodeCollection eller resultatet av GetChildNodes. Anropa ToArray() först för att materialisera noderna som ska modifieras, sedan iterera över den arrayen medan trädet muteras.

En DocumentVisitor-subklass blir inte anropad för vissa innehåll Besökaren anropades via Accept() på en nod som faktiskt inte innehåller målinnehållet, eller den motsvarande Visit* metoden överskuggades inte. Anropa Accept() på en förfader som innehåller innehållet, och överskugga varje Visit*Start / Visit*End par som är relevanta för de nodtyper som bearbetas.

INodeChangingCallback blir inte underrättad om en förändring Återanropet rapporterar bara förändringar på den Document den den registrerades mot. Bekräfta att återanropet är kopplat till den korrekta Document instansen innan förändringen sker, inte efter.

Vanliga frågor

Vad är skillnaden mellan Node och CompositeNode?

Node är basklassen som alla dokumentelement ärver från. CompositeNode utökar Node för element som kan innehålla barn (såsom Body, Paragraph och Table); löv-element som Run ärver direkt från Node och kan inte ha barn.

Hur hittar jag alla noder av en specifik typ i ett dokument?

Anropa CompositeNode.GetChildNodes(nodeType, isDeep) på den nod som är roten för sökningen – ofta Document själv – och skicka med mål-NodeType och isDeep: true för att söka i hela underträdet, inte bara direkta barn.

Hur tar jag bort noder på ett säkert sätt medan jag itererar?

Samla först noderna som ska tas bort i en array – till exempel med NodeCollection.ToArray() – iterera sedan över den arrayen och anropa Remove() på varje nod, istället för att modifiera den levande samlingen medan en foreach itererar den.

Vad är FieldStart, FieldSeparator och FieldEnd noder?

De är NodeType-värden som markerar maskineriet i ett Word-fält inbäddat i körströmmen: FieldStart och FieldEnd binder fältet, och FieldSeparator delar fältets kod från dess för närvarande visade resultat.

Hur bearbetar jag varje stycke, tabell och run i ett dokument?

Skapa en subklass av DocumentVisitor, åsidosätt Visit*Start / Visit*End-metoderna för de nödvändiga nodtyperna, och anropa sedan Accept(visitor) på Document (eller någon subträdrot) för att köra den.

Se även

 Svenska