Jak procházet DOM dokumentu OneNote v Pythonu

Jak procházet DOM dokumentu OneNote v Pythonu

Aspose.Note FOSS for Python představuje soubor sekce OneNote jako strom typovaných objektů Pythonu. Porozumění tomu, jak efektivně procházet tento strom, je základem pro všechny úlohy extrakce obsahu. Tento průvodce pokrývá všechny tři přístupy k procházení: GetChildNodes, přímou iteraci 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í podřízené, 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 nejpohodlně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 mí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í podřízené prvky 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 metody VisitXxxStart/End, 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

Navigování nahoru po stromu

Každý uzel poskytuje 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 dětí

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án):

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

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)
Iterovat pouze přímé potomkyfor child in node
Procházet 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