Hur man arbetar med PDF-data i Python

Hur man arbetar med PDF-data i Python

Aspose.PDF FOSS för Python representerar en PDF-dokuments XMP-metadata som en minnesbaserad datamodell byggd från XmpPacket, XmpField, XmpArray, XmpStruct och XmpProperty objekt, med NamespaceProvider som löser namnrymdsprefix till URI:er. Detta låter dig läsa, bygga och skriva om strukturerad metadata — titlar, datum, nyckelordslistor, anpassade fält — utan att manuellt skriva RDF/XML. Biblioteket är rent Python och installeras med kommandot nedan.

Steg-för-steg-guide

Steg 1: Installera paketet

Installera Aspose.PDF FOSS-paketet:

git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .

Verifiera installationen genom att importera XmpPacket och skriva ut ett bekräftelsemeddelande:

from aspose_pdf import XmpPacket
print("aspose-pdf-foss-for-python is ready.")

Steg 2: Importera nödvändiga klasser

Importera XMP-datamodellklasserna och namnrymdslösaren:

from aspose_pdf import (
    NamespaceProvider,
    XmpArray,
    XmpField,
    XmpPacket,
    XmpProperty,
    XmpStruct,
)

Steg 3: Skapa ett paket och ange enkla egenskaper

XmpPacket() börjar med en tom fältlista. set_value(prefix, name, value, uri=...) sätter eller ersätter en enkel egenskap, och get(prefix_or_uri, name) läser tillbaka den som ett XmpField; get accepterar antingen det registrerade prefixet eller hela namnrymdens URI:

from aspose_pdf import XmpPacket

packet = XmpPacket()
packet.set_value("dc", "title", "Quarterly Report")
packet.set_value(
    "dc", "creator", "Automation Pipeline",
    uri="http://purl.org/dc/elements/1.1/",
)

title_field = packet.get("dc", "title")
print(title_field.value)  # "Quarterly Report"

Steg 4: Lagra typade värden

XmpPacket tillhandahåller typade bekvämlighetsaccessorer som konverterar till och från den vanligtextform som XMP lagrar internt: set_date/get_date, set_int/get_int, set_real/get_real och set_bool/get_bool. Varje getter returnerar None när egenskapen saknas istället för att kasta:

from datetime import datetime

packet.set_date("xmp", "CreateDate", datetime(2026, 7, 29, 9, 30))
packet.set_int("pdf", "PageCount", 42)
packet.set_real("custom", "ConfidenceScore", 0.97, uri="https://example.com/ns/custom/1.0/")
packet.set_bool("custom", "IsFinal", True, uri="https://example.com/ns/custom/1.0/")

print(packet.get_date("xmp", "CreateDate"))
print(packet.get_int("pdf", "PageCount"))
print(packet.get_real("custom", "ConfidenceScore"))
print(packet.get_bool("custom", "IsFinal"))

Steg 5: Lagra lokaliserad text och ordnade arrayer

set_localized_text skriver en språk-alternativ (rdf:Alt) egenskap såsom dc:title på ett specifikt språk, med standardvärde "x-default". set_array skriver en ordnad (Seq), oordnad (Bag) eller alternativ (Alt) array från en vanlig lista med värden, och get_array läser tillbaka den som en lista med strängar:

packet.set_localized_text("dc", "description", "Quarterly summary", lang="en")
packet.set_localized_text(
    "dc", "description", "Resumen trimestral",
    uri="http://purl.org/dc/elements/1.1/", lang="es",
)
print(packet.get_localized_text("dc", "description", lang="es"))

packet.set_array("dc", "subject", ["finance", "quarterly", "internal"], kind="Bag")
print(packet.get_array("dc", "subject"))

Steg 6: Bygg strukturerade värden med XmpStruct

Vissa XMP-egenskaper (dimensionposter, historikposter) är strukturerade värden snarare än enkel text. Bygg ett med XmpStruct, lägg till medlem XmpField objekt med add, och läs tillbaka en medlem med namn med get, sedan fäst strukturen till paketet med add:

dimensions = XmpStruct()
dimensions.add(XmpField(prefix="stDim", name="w", value="612"))
dimensions.add(XmpField(prefix="stDim", name="h", value="792"))
dimensions.add(XmpField(prefix="stDim", name="unit", value="pt"))

print(dimensions.get("w").value)  # "612"

packet.add(XmpField(prefix="xmpTPg", name="MaxPageSize", value=dimensions))

Steg 7: Registrera anpassade XMP-namnrymder

NamespaceProvider är förladdad med de standard XMP-namnrymderna (Dublin Core, Adobe XMP, PDF och andra). Anropa register(prefix, uri) för att lägga till en anpassad mappning — den returnerar leverantören själv så anrop kan kedjas — och fäst sedan leverantören till ett paket så att serialisering kan lösa upp det anpassade prefixet till dess URI:

from aspose_pdf import NamespaceProvider, XmpPacket

provider = NamespaceProvider()
provider.register("custom", "https://example.com/ns/custom/1.0/")

packet = XmpPacket(namespace_provider=provider)
packet.set_value("custom", "batch_id", "run-2026-07-29")

Steg 8: Parsa och serialisera ett paket

XmpPacket.parse(data, provider=...) läser råa XMP-paketbytes eller text till en XmpPacket. serialize() och to_bytes() återger paketet tillbaka till XMP-paketbytes:

xmp_bytes = packet.to_bytes()

restored = XmpPacket.parse(xmp_bytes)
print(restored.get("dc", "title").value)

Vanliga problem och lösningar

get() eller en typad getter returnerar None även om jag just satte egenskapen

Bekräfta att prefix (eller URI) argumentet till get/get_int/get_date/etc. matchar exakt det som skickades till det motsvarande set_* anropet — get matchar både fältets prefix och dess namnrymds-URI, men ett felaktigt anpassat prefix i ett anrop och en URI i det andra kommer att missas.

Anpassat namnrymdsprefix ger ofullständig output vid serialisering

Ett prefix som inte är en av de standard XMP-namnrymderna (dc, xmp, pdf och liknande) kräver antingen ett explicit uri= argument i varje set_* anrop, eller en NamespaceProvider med det prefixet registrerad och bifogad till paketet via XmpPacket(namespace_provider=provider) innan serialize()/to_bytes() anropas.

get_bool, get_int, eller get_real returns None för ett värde jag vet är satt

Dessa typade getters returnerar None när den lagrade texten inte kan parsas som den förväntade typen — till exempel get_int på en egenskap vars värde sattes med set_value som fri text snarare än set_int. Använd den matchande typade settern (set_int, set_real, set_bool) så att getterns parslogik matchar skrivvägen.

XmpPacket.parse raises ValueError på ett paket från en opålitlig källa

parse avvisar alla <!DOCTYPE eller <!ENTITY deklarationer som ett skydd mot fientliga indata mot XXE- och miljard-skratt-attacker. Ett legitimt XMP-paket behöver aldrig en DTD; behandla undantaget som en signal om att källströmmen är felaktig eller osäker snarare än att kringgå skyddet.

get_array returns None istället för en lista

get_array returnerar None när den namngivna egenskapen antingen inte finns eller inte lagrades som en XmpArray (till exempel om den sattes med set_value istället för set_array). Använd set_array när du skriver egenskapen så att det lagrade värdet matchar den form som get_array förväntar sig.

Vanliga frågor

Vad är skillnaden mellan set_value och de typade settarna som set_int?

set_value lagrar vad value du skickar in, oförändrat. De typade settarna (set_date, set_int, set_real, set_bool) konverterar deras indata till den klartextform som XMP använder internt och paras ihop med en matchande typad getter som parsar tillbaka den, så använd dem när du behöver rundresa-typ-säkerhet istället för råa strängar.

Hur skiljer sig XmpArray-typerna (Bag, Seq, Alt)?

Bag är en oordnad mängd av värden, Seq är en ordnad lista, och Alt innehåller alternativa värden (oftast språkvarianter, som används av set_localized_text). Skicka den önskade typen till set_array(..., kind="Bag") eller bygg ett XmpArray(kind=...) direkt.

Kan jag läsa den råa listan av egenskaper på ett paket utan att känna till deras namn i förväg?

Ja — iterera packet.fields, som innehåller varje XmpField, XmpArray och XmpProperty som lagts till i paketet i den ordning de infördes.

Behöver jag en NamespaceProvider för de standard XMP-namnutrymmena?

Nej. dc, xmp, pdf och de andra standardprefixen löses upp automatiskt. En NamespaceProvider behövs endast för anpassade prefix du själv uppfinner.

Hur skiljer sig XmpProperty-kvalificerare från en enkel XmpField?

XmpProperty omsluter en grundläggande XmpField tillsammans med en lista av kvalificerarfält (tillagda med add_qualifier), som används för det mer sällsynta fallet där en egenskap i sig själv behöver ytterligare RDF-metadata kopplad till sitt värde, utöver xml:lang-kvalificeraren som XmpField.language redan täcker.

Se även

 Svenska