Jak procházet DOM dokumentu OneNote v Python

Jak procházet DOM dokumentu OneNote v 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, přímá iterace a DocumentVisitor.


Objektový model dokumentu

DOM OneNote je přísný strom:

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

Každý uzel dědí z Node. Uzly, které mají potomky, dědí z CompositeNode.


Metoda 1: GetChildNodes (rekurzivní, filtrováno podle typu)

CompositeNode.GetChildNodes(Type) provádí rekurzivní prohledávání do hloubky celého podstromu a vrací plochý seznam všech uzlů odpovídajících zadanému typu. Toto je nejužitečnější přístup pro extrakci obsahu:

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)}")

Omezte vyhledávání na jednu stránku voláním GetChildNodes na Page namísto 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")

Metoda 2: Přímá iterace potomků

for child in node iteruje bezprostřední potomky CompositeNode. Použijte to, když potřebujete jednu konkrétní úroveň hierarchie:

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__}")

Metoda 3: DocumentVisitor

DocumentVisitor poskytuje vzor návštěvníka pro strukturované procházení. Přepište pouze VisitXxxStart/End metody, které potřebujete. Návštěvník je vyvolán voláním 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())

Dostupné metody návštěvníka

Pár metodTyp uzlu
VisitDocumentStart/EndDocument
VisitPageStart/EndPage
VisitTitleStart/EndTitle
VisitOutlineStart/EndOutline
VisitOutlineElementStart/EndOutlineElement
VisitRichTextStart/EndRichText
VisitImageStart/EndImage

Navigace nahoru ve stromu

Každý uzel vystavuje ParentNode a Document vlastnost pro navigaci nahoru:

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

Metody správy potomků

CompositeNode také poskytuje správu podřízených v paměti (užitečné pro programovou konstrukci dokumentu, i když zápis zpět do .one není podporováno):

MetodaPopis
node.FirstChildPrvní přímý potomek nebo None
node.LastChildPoslední přímý potomek nebo None
node.AppendChildLast(child)Přidat potomka na konec
node.AppendChildFirst(child)Přidat potomka na začátek
node.InsertChild(index, child)Vložit na pozici
node.RemoveChild(child)Odebrat potomka

Počítání uzlů pomocí návštěvníka

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}")

Výběr správné metody procházení

ScénářNejlepší přístup
Najít všechny uzly jednoho typu (např. všechny RichText)GetChildNodes(RichText)
Procházet pouze přímé potomkyfor child in node
Projít strom s kontextem (hloubka, stav rodiče)DocumentVisitor
Navigovat od obsahu nahoru k rodiči nebo kořeninode.ParentNode / node.Document

Související zdroje:

 Čeština