Jak pracować z węzłami w .NET

Jak pracować z węzłami w .NET

Ten przewodnik pokazuje, jak przechodzić, zapytywać i modyfikować drzewo węzłów dokumentu Word bezpośrednio w Aspose.Words FOSS dla .NET, używając Node and CompositeNode klas bazowych, które Document, Section, Paragraph, Table, i każdy inny element dokumentu jest oparty na nich. Obejmuje określanie zakresu wyszukiwania przez NodeType, dodawanie i usuwanie węzłów programowo, reagowanie na zmiany strukturalne oraz używanie DocumentVisitor do przeglądania z rozdzieleniem wg typów.

Przewodnik krok po kroku

Krok 1: Zainstaluj pakiet

Aspose.Words FOSS dla .NET nie publikuje jeszcze pakietu NuGet — zbuduj bibliotekę z kodu źródłowego. Sklonuj https://github.com/aspose-words-foss/Aspose.Words-FOSS-for-.NET.git, a następnie zbuduj Aspose.Words.sln w konfiguracji Release przy użyciu SDK .NET i odwołaj się do powstałego zestawu Aspose.Words w swoim projekcie. Biblioteka celuje w .NET Standard 2.0, więc działa na .NET Framework 4.6.2+ oraz .NET 6/8/10.


Krok 2: Zaimportuj wymagane klasy

Dodaj dyrektywę using Aspose.Words; — Node, CompositeNode, NodeType, NodeCollection, NodeList, INodeChangingCallback oraz DocumentVisitor znajdują się w przestrzeni nazw Aspose.Words razem z Document.


Krok 3: Zrozum Node i klasy bazowe CompositeNode

Każdy obiekt w drzewie dokumentu dziedziczy po abstrakcyjnej klasie Node, która udostępnia NodeType (identyfikujący, jakiego rodzaju węzeł to jest), ParentNode (otaczający CompositeNode), Document (dokument właściciel) oraz PreviousSibling / NextSibling do przemieszczania się po węzłach na tym samym poziomie. Sprawdź Node.IsComposite, aby dowiedzieć się, czy dany węzeł może zawierać dzieci przed rzutowaniem go. CompositeNode rozszerza Node dla elementów kontenerowych — FirstChild, LastChild i Count opisują jego bezpośrednie dzieci, a HasChildNodes informuje, czy jakiekolwiek istnieją.


Krok 4: Zapytaj o dzieci według typu

Wywołaj CompositeNode.GetChildNodes(nodeType, isDeep), aby pobrać każde dziecko danego NodeType, przekazując isDeep: true, aby przeszukać całe poddrzewo zamiast tylko bezpośrednich dzieci, lub NodeType.Any, aby dopasować każdy typ węzła niezależnie od rodzaju. CompositeNode.GetChild(nodeType, index, isDeep) pobiera pojedyncze pasujące dziecko według indeksu. Dla typów strukturalnych węzłów (Document, Section, Body, Paragraph, Table, Row, Cell), typów treści inline (Run, Shape, Comment) oraz typów mechanizmu pól (FieldStart, FieldSeparator, FieldEnd, które oznaczają granice pola Word i zmieniają tekst w strumieniu uruchomienia), przekaż konkretną wartość NodeType, która identyfikuje, czego szukasz.


Krok 5: Wykonaj zapytania XPath w poddrzewie

CompositeNode implementuje również SelectNodes(xpath) i SelectSingleNode(xpath) dla zapytań opartych na XPath w poddrzewie, zwracając dopasowania jako NodeList (lub pojedynczy Node). CompositeNode.GetEnumerator() obsługuje prosty foreach nad bezpośrednimi dziećmi węzła, gdy zapytanie XPath jest większe niż wymaga zadanie.


Krok 6: Dodaj, przenieś i usuń węzły

Aby zmodyfikować drzewo, wywołaj AppendChild(newChild) lub PrependChild(newChild), aby dodać węzeł na początku lub na końcu dzieci kontenera, oraz InsertBefore(newChild, refChild) lub InsertAfter(newChild, refChild), aby wstawić w odniesieniu do istniejącego dziecka. RemoveChild(oldChild) usuwa jedno dziecko, a RemoveAllChildren() usuwa wszystkie dzieci jednocześnie; CompositeNode.IndexOf(child) informuje o pozycji dziecka. Na samym Node, Clone(isCloneChildren) kopiuje węzeł — opcjonalnie wraz z jego dziećmi — i Remove() odłącza węzeł od jego rodzica.


Krok 7: Umaterializuj węzły przed modyfikacją żywej kolekcji

Modyfikowanie kolekcji w trakcie, gdy pętla foreach iteruje po niej — niezależnie od tego, czy jest to NodeCollection, czy wynik GetChildNodes — powoduje błąd. Najpierw wywołaj ToArray() na kolekcji, aby umaterializować węzły w stałą tablicę, a następnie iteruj po tej tablicy, wywołując Remove() lub wprowadzając inne zmiany w drzewie.


Krok 8: Przeskanuj poddrzewo w kolejności dokumentu

Node.NextPreOrder(rootNode) i PreviousPreOrder(rootNode) przechodzą drzewo w kolejności dokumentu, ograniczone do podanego węzła korzenia — powszechny sposób skanowania całego poddrzewa węzeł po węźle bez pisania rekurencyjnego kodu przeglądania.


Krok 9: Przetwarzaj każdy typ węzła za pomocą DocumentVisitor

Aby przetwarzać wiele różnych typów węzłów w uporządkowany sposób, utwórz podklasę abstrakcyjnej klasy DocumentVisitor i nadpisz metody Visit*Start / Visit*End dla interesujących typów węzłów — na przykład VisitParagraphStart / VisitParagraphEnd, VisitSectionStart / VisitSectionEnd, VisitBodyStart / VisitBodyEnd — a następnie wywołaj Node.Accept(visitor) na korzeniu poddrzewa, aby go uruchomić. Jest to standardowy wzorzec eksportowania, transformacji lub inspekcji dokumentu bez pisania własnego rekurencyjnego przeglądania dla każdego przypadku użycia.


Krok 10: Reaguj na zmiany strukturalne wprowadzone przez inny kod

Zaimplementuj INodeChangingCallback, gdy kod musi reagować na wstawienia lub usunięcia dokonane przez inny kod — w tym wbudowane operacje — a nie tylko na zmiany wprowadzane bezpośrednio. Jego metody NodeInserting(args), NodeInserted(args), NodeRemoving(args) i NodeRemoved(args) otrzymują każdy NodeChangingArgs opisujący dotknięty Node, jego starego i nowego rodzica oraz NodeChangingAction (Insert lub Remove), które miało miejsce.

Typowe problemy i rozwiązania

Rzutowanie węzła na CompositeNode powoduje błąd nieprawidłowego rzutowania Węzeł jest typu liścia – na przykład Run or FieldStart – który nie może zawierać dzieci. Sprawdź Node.IsComposite najpierw, lub użyj NodeType aby potwierdzić, że węzeł jest typu kontenera przed rzutowaniem.

GetChildNodes zwraca bezpośrednie dzieci, gdy isDeep jest false isDeep zostało pominięte false (lub pominięte, gdy przeciążenie domyślnie jest płytkie). Przekaż isDeep: true to GetChildNodes() aby przeszukać całe poddrzewo zamiast bezpośrednich dzieci.

Modyfikowanie kolekcji podczas iteracji po niej powoduje błąd Węzły zostały dodane lub usunięte wewnątrz a foreach nad a NodeCollection lub wyniku GetChildNodes. Wywołaj ToArray() najpierw, aby materializować węzły do modyfikacji, a następnie iterować po tej tablicy, jednocześnie mutując drzewo.

Podklasa DocumentVisitor nie jest wywoływana dla niektórych treści Odwiedzający został wywołany poprzez Accept() na węźle, który faktycznie nie zawiera docelowej treści, lub odpowiedni Visit* metoda nie została nadpisana. Wywołaj Accept() na przodku, który zawiera treść, i nadpisz każdy Visit*Start / Visit*End para istotna dla przetwarzanych typów węzłów.

INodeChangingCallback nie jest powiadamiany o zmianie Wywołanie zwrotne zgłasza zmiany tylko w Document którą zostało zarejestrowane. Upewnij się, że wywołanie zwrotne jest podłączone do właściwego Document instancji przed wystąpieniem zmiany, a nie po niej.

Najczęściej zadawane pytania

Jaka jest różnica między Node a CompositeNode?

Node jest klasą bazową, z której dziedziczy każdy element dokumentu. CompositeNode rozszerza Node dla elementów, które mogą zawierać dzieci (takie jak Body, Paragraph i Table); elementy liściaste, takie jak Run, dziedziczą bezpośrednio z Node i nie mogą posiadać dzieci.

Jak znaleźć wszystkie węzły określonego typu w dokumencie?

Wywołaj CompositeNode.GetChildNodes(nodeType, isDeep) na węźle, który jest korzeniem wyszukiwania – często na samym Document – przekazując docelowy NodeType i isDeep: true, aby przeszukać całe poddrzewo, a nie tylko bezpośrednie dzieci.

Jak bezpiecznie usuwać węzły podczas iteracji?

Najpierw zbierz węzły do usunięcia w tablicę – na przykład przy użyciu NodeCollection.ToArray() – a następnie iteruj po tej tablicy i wywołaj Remove() na każdym węźle, zamiast modyfikować żywą kolekcję podczas gdy foreach ją iteruje.

Co to są węzły FieldStart, FieldSeparator i FieldEnd?

Są to wartości NodeType oznaczające mechanizm pola Word osadzonego w strumieniu uruchamiania: FieldStart i FieldEnd wiążą pole, a FieldSeparator oddziela kod pola od aktualnie wyświetlanego wyniku.

Jak przetworzyć każdy akapit, tabelę i ciąg w dokumencie?

Utwórz podklasę DocumentVisitor, przesłoń metody Visit*Start / Visit*End dla potrzebnych typów węzłów, a następnie wywołaj Accept(visitor) na Document (lub dowolnym korzeniu poddrzewa), aby ją uruchomić.

Zobacz także

 Polski