Cómo recorrer el DOM del documento OneNote en Python

Cómo recorrer el DOM del documento OneNote en Python

Aspose.Note FOSS for Python represents a OneNote section file as a tree of typed Python objects. Understanding how to traverse this tree efficiently is the foundation for all content extraction tasks. This guide covers all three traversal approaches: GetChildNodes, iteración directa, y DocumentVisitor.


El Modelo de Objetos del Documento

El DOM de OneNote es un árbol estricto:

Document
  ├── Page
  │     ├── Title
  │     │     ├── TitleText (RichText)
  │     │     ├── TitleDate (RichText)
  │     │     └── TitleTime (RichText)
  │     └── Outline
  │           └── OutlineElement
  │                 ├── RichText
  │                 ├── Image
  │                 ├── AttachedFile
  │                 └── Table
  │                       └── TableRow
  │                             └── TableCell
  │                                   └── RichText / Image
  └── Page  (next page ...)

Cada nodo hereda de Node. Los nodos que tienen hijos heredan de CompositeNode.


Método 1: GetChildNodes (Recursivo, filtrado por tipo)

CompositeNode.GetChildNodes(Type) realiza una búsqueda recursiva en profundidad de todo el subárbol y devuelve una lista plana de todos los nodos que coinciden con el tipo dado. Este es el enfoque más conveniente para la extracción de contenido:

from aspose.note import Document, RichText, Image, Table, AttachedFile

doc = Document("MyNotes.one")

##All RichText nodes anywhere in the document
texts = doc.GetChildNodes(RichText)
print(f"RichText nodes: {len(texts)}")

##All images
images = doc.GetChildNodes(Image)
print(f"Image nodes: {len(images)}")

##All tables
tables = doc.GetChildNodes(Table)
print(f"Table nodes: {len(tables)}")

##All attachments
attachments = doc.GetChildNodes(AttachedFile)
print(f"AttachedFile nodes: {len(attachments)}")

Limita la búsqueda a una sola página llamando a GetChildNodes en Page en lugar de Document:

from aspose.note import Document, Page, RichText

doc = Document("MyNotes.one")
for page in doc.GetChildNodes(Page):
    page_texts = page.GetChildNodes(RichText)
    print(f"  Page has {len(page_texts)} text nodes")

Método 2: Iteración directa de hijos

for child in node itera el inmediato hijos de un CompositeNode. Usa esto cuando necesites un nivel específico de la jerarquía:

from aspose.note import Document

doc = Document("MyNotes.one")

##Direct children of Document are Pages
for page in doc:
    title = (
        page.Title.TitleText.Text
        if page.Title and page.Title.TitleText
        else "(untitled)"
    )
    print(f"Page: {title}")
    # Direct children of Page are Outlines (and optionally Title)
    for child in page:
        print(f"  {type(child).__name__}")

Método 3: DocumentVisitor

DocumentVisitor proporciona un patrón de visitante para el recorrido estructurado. Sobrescriba solo el VisitXxxStart/End métodos que necesite. El visitante se despacha llamando a doc.Accept(visitor):

from aspose.note import (
    Document, DocumentVisitor, Page, Title,
    Outline, OutlineElement, RichText, Image,
)

class StructurePrinter(DocumentVisitor):
    def __init__(self):
        self._depth = 0

    def _indent(self):
        return "  " * self._depth

    def VisitPageStart(self, page: Page) -> None:
        t = page.Title.TitleText.Text if page.Title and page.Title.TitleText else "(untitled)"
        print(f"{self._indent()}Page: {t!r}")
        self._depth += 1

    def VisitPageEnd(self, page: Page) -> None:
        self._depth -= 1

    def VisitOutlineStart(self, outline) -> None:
        self._depth += 1

    def VisitOutlineEnd(self, outline) -> None:
        self._depth -= 1

    def VisitRichTextStart(self, rt: RichText) -> None:
        if rt.Text.strip():
            print(f"{self._indent()}Text: {rt.Text.strip()!r}")

    def VisitImageStart(self, img: Image) -> None:
        print(f"{self._indent()}Image: {img.FileName!r} ({img.Width}x{img.Height}pts)")

doc = Document("MyNotes.one")
doc.Accept(StructurePrinter())

Métodos de visitante disponibles

Par de métodosTipo de nodo
VisitDocumentStart/EndDocument
VisitPageStart/EndPage
VisitTitleStart/EndTitle
VisitOutlineStart/EndOutline
VisitOutlineElementStart/EndOutlineElement
VisitRichTextStart/EndRichText
VisitImageStart/EndImage

Navegando hacia arriba en el árbol

Cada nodo expone ParentNode y un Document propiedad para navegar hacia arriba:

from aspose.note import Document, RichText

doc = Document("MyNotes.one")
for rt in doc.GetChildNodes(RichText):
    parent = rt.ParentNode   # OutlineElement, TableCell, Title, etc.
    root = rt.Document       # always the Document root
    print(f"  '{rt.Text.strip()!r}' parent={type(parent).__name__}")
    break

Métodos de gestión de hijos

CompositeNode también expone la gestión de hijos en memoria (útil para la construcción programática de documentos, aunque la escritura de vuelta a .one no está soportado):

MétodoDescripción
node.FirstChildPrimer hijo directo o None
node.LastChildÚltimo hijo directo o None
node.AppendChildLast(child)Agregar hijo al final
node.AppendChildFirst(child)Agregar hijo al inicio
node.InsertChild(index, child)Insertar en posición
node.RemoveChild(child)Eliminar un hijo

Contar nodos con un visitante

from aspose.note import Document, DocumentVisitor, Page, RichText, Image

class Counter(DocumentVisitor):
    def __init__(self):
        self.pages = self.texts = self.images = 0

    def VisitPageStart(self, page: Page) -> None:
        self.pages += 1

    def VisitRichTextStart(self, rt: RichText) -> None:
        self.texts += 1

    def VisitImageStart(self, img: Image) -> None:
        self.images += 1

doc = Document("MyNotes.one")
c = Counter()
doc.Accept(c)
print(f"Pages={c.pages}  RichText={c.texts}  Images={c.images}")

Elegir el método de recorrido adecuado

EscenarioMejor enfoque
Encontrar todos los nodos de un tipo (p. ej., todos los RichText)GetChildNodes(RichText)
Iterar solo hijos directosfor child in node
Recorrer el árbol con contexto (profundidad, estado del padre)DocumentVisitor
Navegar desde el contenido hasta el padre o la raíznode.ParentNode / node.Document

Recursos relacionados:

 Español