Wie man mit PDF-Daten in Python arbeitet
Aspose.PDF FOSS für Python stellt die XMP-Metadaten eines PDF-Dokuments als ein im Speicher befindliches Datenmodell dar, das aus XmpPacket, XmpField, XmpArray, XmpStruct und XmpProperty-Objekten aufgebaut ist, wobei NamespaceProvider Namespace-Präfixe in URIs auflöst. Das ermöglicht das Lesen, Erstellen und Umschreiben strukturierter Metadaten — Titel, Daten, Stichwortlisten, benutzerdefinierte Felder — ohne manuelles Schreiben von RDF/XML. Die Bibliothek ist reines Python und wird mit dem untenstehenden Befehl installiert.
Schritt-für-Schritt-Anleitung
Schritt 1: Paket installieren
Installieren Sie das Aspose.PDF FOSS-Paket:
git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .Überprüfen Sie die Installation, indem Sie XmpPacket importieren und eine Bestätigungsnachricht ausgeben:
from aspose_pdf import XmpPacket
print("aspose-pdf-foss-for-python is ready.")Schritt 2: Erforderliche Klassen importieren
Importieren Sie die XMP-Datenmodellklassen und den Namensraumauflöser:
from aspose_pdf import (
NamespaceProvider,
XmpArray,
XmpField,
XmpPacket,
XmpProperty,
XmpStruct,
)Schritt 3: Ein Packet erstellen und einfache Eigenschaften festlegen
XmpPacket() beginnt mit einer leeren Feldliste. set_value(prefix, name, value, uri=...) setzt oder ersetzt eine einfache Eigenschaft, und get(prefix_or_uri, name) liest sie als XmpField zurück; get akzeptiert entweder das registrierte Präfix oder die vollständige Namespace-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"Schritt 4: Typisierte Werte speichern
XmpPacket bietet typisierte Komfortzugriffe, die von und in die von XMP intern gespeicherte Klartextform konvertieren: set_date/get_date, set_int/get_int, set_real/get_real und set_bool/get_bool. Jeder Getter gibt None zurück, wenn die Eigenschaft fehlt, anstatt eine Ausnahme zu werfen:
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"))Schritt 5: Lokalisierte Texte und geordnete Arrays speichern
set_localized_text schreibt eine sprachalternierende (rdf:Alt) Eigenschaft wie dc:title in einer bestimmten Sprache, wobei "x-default" standardmäßig verwendet wird. set_array schreibt ein geordnetes (Seq), ungeordnetes (Bag) oder alternatives (Alt) Array aus einer einfachen Werteliste und get_array liest es als Liste von Zeichenketten zurück:
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"))Schritt 6: Strukturierte Werte mit XmpStruct erstellen
Einige XMP-Eigenschaften (Dimensionsdatensätze, Verlaufseinträge) sind strukturierte Werte und keine einfachen Texte. Erstellen Sie einen mit XmpStruct, fügen Sie Mitglied XmpField Objekte mit add hinzu und lesen Sie ein Mitglied anhand des Namens mit get aus, dann hängen Sie die Struktur mit add an das Paket an:
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))Schritt 7: Benutzerdefinierte XMP-Namensräume registrieren
NamespaceProvider ist mit den Standard-XMP-Namensräumen (Dublin Core, Adobe XMP, PDF und weitere) vorbelegt. Rufen Sie register(prefix, uri) auf, um eine benutzerdefinierte Zuordnung hinzuzufügen—sie gibt den Provider selbst zurück, sodass Aufrufe verkettet werden können—und hängen Sie dann den Provider an ein Paket, damit die Serialisierung das benutzerdefinierte Präfix in seine URI auflösen kann:
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")Schritt 8: Ein Paket parsen und serialisieren
XmpPacket.parse(data, provider=...) liest rohe XMP-Paket-Bytes oder Text in ein XmpPacket. serialize() und to_bytes() rendern das Paket beide zurück in XMP-Paket-Bytes:
xmp_bytes = packet.to_bytes()
restored = XmpPacket.parse(xmp_bytes)
print(restored.get("dc", "title").value)Häufige Probleme und Lösungen
get() oder ein typisierter Getter zurückgibt None obwohl ich die Eigenschaft gerade gesetzt habe
Bestätigen Sie, dass das prefix-Argument (oder URI) für get/get_int/get_date/etc. exakt dem entspricht, was an den entsprechenden set_*-Aufruf übergeben wurde — get prüft sowohl den Präfix des Feldes als auch dessen Namespace-URI, aber ein nicht übereinstimmender benutzerdefinierter Präfix in einem Aufruf und ein URI im anderen führen zu einem Fehlmatch.
Benutzerdefinierter Namespace-Präfix erzeugt unvollständige Ausgabe bei Serialisierung
Ein Präfix, das nicht zu den Standard-XMP-Namespaces gehört (dc, xmp, pdf usw.), benötigt entweder ein explizites uri=-Argument bei jedem set_*-Aufruf oder ein NamespaceProvider, bei dem dieser Präfix registriert und dem Paket über XmpPacket(namespace_provider=provider) zugewiesen wurde, bevor serialize()/to_bytes() aufgerufen werden.
get_bool, get_int, oder get_real returns None für einen Wert, von dem ich weiß, dass er gesetzt ist
Diese typisierten Getter geben None zurück, wenn der gespeicherte Text nicht in den erwarteten Typ geparst werden kann — zum Beispiel get_int bei einer Eigenschaft, deren Wert mit set_value als Freitext statt mit set_int gesetzt wurde. Verwenden Sie den entsprechenden typisierten Setter (set_int, set_real, set_bool), damit die Parsing-Logik des Getters dem Schreibpfad entspricht.
XmpPacket.parse raises ValueError bei einem Paket aus einer nicht vertrauenswürdigen Quelle
parse verwirft jede <!DOCTYPE- oder <!ENTITY-Deklaration als Schutzmaßnahme gegen feindliche Eingaben (XXE und Billion-Laughs-Angriffe). Ein legitimes XMP-Paket benötigt niemals ein DTD; behandeln Sie die Ausnahme als Hinweis darauf, dass der Quellstrom fehlerhaft oder unsicher ist, anstatt die Schutzmaßnahme zu umgehen.
get_array returns None statt einer Liste
get_array gibt None zurück, wenn die benannte Eigenschaft entweder nicht existiert oder nicht als XmpArray gespeichert wurde (z.B. wenn sie mit set_value anstelle von set_array gesetzt wurde). Verwenden Sie set_array, wenn Sie die Eigenschaft schreiben, damit der gespeicherte Wert der von get_array erwarteten Struktur entspricht.
Häufig gestellte Fragen
Was ist der Unterschied zwischen set_value und den typisierten Settern wie set_int?
set_value speichert alles, was value Sie übergeben, unverändert. Die typisierten Setter (set_date, set_int, set_real, set_bool) konvertieren ihre Eingabe in die reine Textform, die XMP intern verwendet, und passen zu einem entsprechenden typisierten Getter, der sie wieder einliest. Verwenden Sie sie also, wenn Sie Rundweg-Typensicherheit benötigen statt roher Zeichenketten.
Wie unterscheiden sich die XmpArray-Typen (Bag, Seq, Alt)?
Bag ist eine ungeordnete Menge von Werten, Seq ist eine geordnete Liste und Alt enthält alternative Werte (meist Sprachalternativen, wie sie von set_localized_text verwendet werden). Übergeben Sie den gewünschten Typ an set_array(..., kind="Bag") oder erstellen Sie ein XmpArray(kind=...) direkt.
Kann ich die rohe Liste von Eigenschaften eines Pakets auslesen, ohne ihre Namen im Voraus zu kennen?
Ja — iterieren Sie packet.fields, das jedes XmpField, XmpArray und XmpProperty enthält, die in Einfügereihenfolge zum Paket hinzugefügt wurden.
Brauche ich ein NamespaceProvider für die standardmäßigen XMP-Namensräume?
Nein. dc, xmp, pdf und die anderen Standardpräfixe werden automatisch aufgelöst. Ein NamespaceProvider wird nur für benutzerdefinierte Präfixe benötigt, die Sie selbst erfinden.
Wie unterscheiden sich XmpProperty-Qualifizierer von einem einfachen XmpField?
XmpProperty umschließt ein Basis-XmpField zusammen mit einer Liste von Qualifikator-Feldern (hinzugefügt mit add_qualifier), die für den selteneren Fall verwendet wird, in dem eine Eigenschaft selbst zusätzliche RDF-Metadaten an ihrem Wert benötigt, über den xml:lang-Qualifizierer hinaus, den XmpField.language bereits abdeckt.