Bindery og dokumenter uden limkode
Filen var ikke problemet
Den første fejl er at tro, at dokumentet er filen. Den ankommer som en fil, ja. Den har et navn, normalt med en endelse, der ser betryggende ud. Indkøbsregnearket siger .xlsx, rapporten siger .docx, arkivudtrækket siger .pdf, og alle lader, som om verden er blevet enkel, fordi de sidste fire tegn ser velkendte ud. Dejligt. Så lyver endelsen, regnearket har skjulte ark, præsentationen indeholder indlejrede objekter, PDF'en er for det meste tekst, men ikke helt, og den gamle Word-fil lugter stadig svagt af 2003.
De fleste teams bygger ikke en dokumentpipeline. De bygger et lille museum af formatafvigelser. Ét bibliotek til Word, et andet til Excel, noget andet til PDF'er, et heroisk shell-script til arkivmappen, en Python-pakke, der sidst blev opdateret, da alle stadig syntes, at QR-koder var spændende, og et par regulære udtryk, der burde tages med udenfor og få en stille pension. Seks måneder senere er limlaget større end produktet. Dette er ikke en sjælden fejltilstand. Dette er den normale form for dokumentarbejde, når hvert format får sit eget kongerige.
Bindery findes, fordi dokumentlaget ikke skal blive hovedprojektet. På implementeringsniveau er det en Rust-crate ved navn dweve-bindery. Den offentlige side beskriver én crate med 17 formater, DocQL, Python-bindinger og en fælles motor. Det vigtige er, at højtstående API'er som Document, Presentation og Workbook ligger over formatspecifikke moduler til OLE2, OOXML, ODF, iWork, RTF, PDF, Markdown, EPUB, LaTeX, billeder, formler og DocQL. Den liste er ikke der for at imponere nogen. Den er der, fordi rigtige korpora er uhøflige.
Den nyttige påstand er enkel: åbn dokumentet gennem én motor, normaliser det, der kan normaliseres, og hold den formatspecifikke smerte under en fælles overflade. Det gør ikke hvert format identisk. Det gør forskellene eksplicitte nok til, at en pipeline kan overleve dem.
Registrering er ikke en dekoration
Formatregistrering lyder som et lille værktøj, indtil det fejler. Så bliver det hele hændelsen. Endelser er metadata leveret af den person, det værktøj, den mailgateway, det eksportjob, det migrationsscript eller den trætte praktikant, der sidst rørte ved filen. Nogle gange er de rigtige. Nogle gange er de en høflig anbefaling. En seriøs dokumentmotor bør inspicere magic bytes, containerstruktur, pakkedele, streams og interne signaler, før den beslutter, hvilken læser der ejer filen.
Bindery behandler det som hoveddøren. README'en og siden beskriver begge automatisk formatregistrering. Biblioteksdokumentationen viser Document::open og Presentation::open som den normale vej, ikke en vælg-din-parser-ceremoni. Det betyder noget, fordi brugere ikke ønsker et kursus i dokumentarkæologi, før de kan udtrække en tabel. De ønsker, at motoren vælger stien og derefter giver dem et stabilt API.
Der er en tør lille lektie her. Jo mindre glamour en komponent har, jo mere skade kan den gøre, når folk vifter den væk. Registrering er ikke glamourøst. Det er heller ikke kodningskonvertering, ZIP-håndtering, OLE-mappegennemgang, relationsopløsning, Snappy-dekomprimering eller XML-navneområdehåndtering. Fint. Det kedelige arbejde er præcis der, hvor produktionspipeliner enten bliver pålidelige eller begynder at samle held og lykke-amuletter.
Én model betyder ikke én løgn
En samlet API kan blive farlig, når den lader som om forskellene er forsvundet. Bindery bør ikke påstå, at en PDF, et regneark, et iWork-arkiv og en OOXML-pakke er det samme dyr iført forskellige hatte. Det er de ikke. Den nyttige arkitektur er ikke at flade sandheden ud til grød. Den er at eksponere fælles operationer, hvor de er fælles, og holde kapabilitetsgrænser synlige, hvor de ikke er.
Kildeopsætningen viser den opdeling. Der er en samlet Word-dokument-API, en samlet præsentations-API, regnearksegenskaber, formelberegning bag features, DocQL-forbindelser og moduler på lavere niveau for selve formaterne. Den offentlige formatmatrix siger, at OOXML og ODF er førsteklasses overflader til læsning, skrivning og forespørgsler. PDF og RTF er læsetunge og mere forsigtige ved skrivning. EPUB, LaTeX og Markdown er outputformater. Legacy Office og iWork har deres egen interne maskineri. Det er den rette holdning. Én motor, ja. Én fantasi, nej.
Denne skelnen betyder noget i audits og dataprodukter. Hvis en compliance-workflow udtrækker klausuler fra kontrakter, skal den vide, om en værdi kom fra et afsnit, en tabelcelle, en slidenote, en formel eller en PDF-tekstkørsel. Hvis et indlæsningsjob fodrer retrieval, skal det vide, om billeder, kommentarer, metadata og relationer blev bevaret, ignoreret eller markeret som ikke-understøttede. Svaret kan ikke begraves i en parser-specifik fodnote, for den fodnote dukker ikke op, når nogen spørger, hvorfor resultatet ændrede sig.
Dokumenter er strukturerede data, der glemte at indrømme det
Det værste, en dokumentpipeline kan gøre, er at reducere alt til tekst for tidligt. Tekst er nyttig. Tekst er ikke hele dokumentet. Et regneark har formler, referencer, ark, rækker, celler, talformater, kommentarer og regnearksstruktur. En præsentation har slides, figurer, billeder, noter, rækkefølge og nogle gange en virksomhedsskabelon, der har overlevet tre fusioner og ét rebrand gennem ren ondskab. Et Word-dokument har afsnit, kørsler, tabeller, sidehoveder, sidefødder, typografier, relationer og indlejrede objekter. En PDF har streams og layoutbeslutninger, der måske eller måske ikke svarer til læserækkefølgen. At gøre alt det til én flad streng er hurtigt, betryggende og ofte forkert.
Bindery’s API’er på højt niveau er nyttige, fordi de holder dokumentets form i live længe nok til at stille bedre spørgsmål. Dokument-API’en eksponerer afsnit, kørsler, tabeller, rækker og celler. Regnearksmodulet eksponerer workbook- og worksheet-egenskaber. Formelmotoren dækker en stor Excel-kompatibel funktionsflade. DocQL tilføjer et SQL-lignende forespørgselssprog over dokumentmodellen med lexer, parser, validator, planner, executor, forbindelser, værdier og funktioner i kildetræet. Det er mere end en bekvemmelighedsindpakning. Det er en måde at stoppe med at omskrive den samme udtrækningslogik for hvert format.
Forestil dig at stille ét korpus-spørgsmål: hvilke celler refererer til denne antagelse, hvilke tabeller indeholder en risikokategori, hvilke slides nævner en politik, hvilke dokumenter har en brugerdefineret egenskab, og hvilke formler afhænger af en given input. I per-format-riget bliver det fire scripts og et regneark fuld af undskyldninger. I en delt model bliver det en forespørgselsflade. Stadig arbejde, selvfølgelig. Software giver dig sjældent en ferie i gave. Men det er det rigtige arbejde.
Hvorfor Rust er et fornuftigt valg til dette rod
Dokumentformater er en vidunderlig kombination af binære strukturer, komprimerede pakker, XML, ældre kodninger, billeddata, datostystemer, formelsemantik og sikkerhedsbekymringer. Med andre ord den slags arbejde, hvor vag hukommelsesejerskab er en livsstil med fakturaer til følge. Rust er en fornuftig base, fordi Bindery skal lave omhyggelig parsing, håndtere buffere, håndtere fejl tydeligt og udstille API'er, der ikke får resten af stakken til at gætte på, hvad der gik galt.
Crate-funktionerne fortæller samme historie. Standardfunktionerne inkluderer OLE, OOXML, OOXML-kryptering og eval-motoren. Fuld support aktiverer iWork, ODF, RTF, formler, billedkonvertering, skrifttyper og meget mere. DocQL er en funktion med sin egen binær. Valgfrie afhængigheder flugter med de formater og overflader, de understøtter: ZIP-håndtering, hurtig XML-parsing, kodningskonvertering, Snappy, protobuf, billedafkodning, statistik og komplekse tal til formelarbejde, og så videre. Dette er ikke én kæmpe klump, der lader som om alle afhængigheder hører til overalt. Funktionsflag holder dokumentmotorens form synlig.
Det betyder noget for indlejring. Et videnssystem ønsker måske den fulde kontor- og forespørgselsflade. En lille tjeneste ønsker måske kun OOXML og tekstudtræk. En Python-arbejdsgang ønsker måske bindinger over den samme motor. En kommandolinjeinspektionssti kan være nyttig til engangsforespørgsler og tests. Siden taler om Rust, PyO3 og en CLI-flade; kilden viser en DocQL-binær og en PyO3-pakke. Det vigtige designvalg er, at disse indgangspunkter sidder på én motor. Ellers bliver hver integration sin egen lidt anderledes sandhed, og så begynder fejlrapporterne at have forskellige hatte på.
Vedligeholdelseshistorien er produkthistorien
Bindery er let at beskrive som en parser, men vedligeholdelseshistorien er den egentlige produkthistorie. Hvert nyt formatbibliotek, der tilføjes til en pipeline, har sin egen udgivelsesrytme, fejlvokabular, fejltyper, særheder, afhængighedsrisiko, testfixtures og fejltilstande. I lille skala ser det håndterbart ud. I korpusskala bliver det et operationelt arkivskab, der bider.
En delt motor fjerner ikke formatkompleksitet. Det ville være mistænkeligt. Den flytter kompleksiteten til et sted, hvor tests, kapabilitetsetiketter, funktioner og API'er kan styres sammen. README'en har end-to-end-tests for dokument-, præsentations-, regnearks-, iWork- og andre formater. Kildetræet har moduler, der gør formatgrænser tydelige. Den struktur er det, der lader et team forbedre parserlaget uden at bede hvert produktteam om at lære forskellen mellem en relationsdel og en sammensat filstrøm igen.
Det er derfor, Bindery passer ind i resten af Dweve-stakken. Reed handler om parsing med kvitteringer. BitWeave handler om deterministisk hentning. Fabric og Spindle handler om styret viden og operationel brug. Bindery ligger før disse lag. Det omdanner kontordokumenter til struktureret materiale, som resten af stakken kan ræsonnere om. Hvis inputlaget er lim og håb, arver downstream-systemet lim og håb. Meget effektivt, hvis din strategiske målsætning er fremtidig lidelse.
Hvad du skal spørge om, før du adopterer det
Det første spørgsmål er ikke, om Bindery understøtter din foretrukne filtype. Det er et checkliste-spørgsmål, og checklister er gode, men det er ikke nok. Det bedre spørgsmål er, hvilke dokumentløfter du har brug for. Har du brug for skrivebeskyttet ekstraktion, skriveunderstøttelse, round-trip-bevarelse, formelberegning, forespørgsler på tværs af formater, metadata, indlejrede billeder, krypteret OOXML, ældre Office, iWork, ODF eller output til EPUB, LaTeX og Markdown? Det er forskellige opgaver. At lade som om, de er én opgave, er sådan, køreplaner bliver til suppe.
Det andet spørgsmål er, hvordan fejl bliver synliggjort. Hvis en parser ikke kan bevare en struktur, siger den det så? Hvis en writer er best-effort, er det så synligt? Hvis en formel ikke kan beregnes, kan kalderen så beslutte, om den skal blokere, advare eller fortsætte? En dokumentmotor er ikke pålidelig, fordi den aldrig siger nej. Den er pålidelig, fordi dens nej er typet, specifikt og tæt på problemet.
Det tredje spørgsmål er, hvordan du tester din egen korpus. Offentlige eksempler er nyttige, men dit arkiv er sandsynligvis mærkeligere end eksempelmappen. Det indeholder ødelagte eksporter, gamle skabeloner, mærkelige talformater, skjulte regneark, kopierede tabeller, fejlbehæftede PDF’er og filer med navnet final_final_really_final. Bindery giver en fælles motor og testbare overflader. Du har stadig brug for korpustests. Desværre bliver dokumenterne ikke voksne af sig selv.
Lærdommen
Lærdommen fra Bindery er, at dokumentbehandling ikke er tekstudtrækning med ekstra trin. Det er formatgenkendelse, strukturel parsing, kapacitetsgrænser, forespørgselsflader, skriveveje og vedligeholdelsesdisciplin. Brugeren ser en fil. Systemet ser en container, streams, relationer, poster, stilarter, formler, metadata, kodninger og outputløfter. En god motor holder den kompleksitet under produktets overflade uden at lade, som om den ikke findes.
Bindery’s opgave er at gøre dokumentlaget kedeligt i den gode forstand. Én Rust-motor. Højniveau-API’er til dokumenter, præsentationer og regneark. Formatmoduler til de rodede dele. DocQL til fælles spørgsmål. Python- og stackintegration, hvor det er nyttigt. Kapacitetsetiketter i stedet for formatmytologi.
Filen var aldrig problemet. Limen var. Bindery er forsøget på at stoppe med at betale husleje for det limlag.