כיצד לעבוד עם נתוני PDF ב-Python
Aspose.PDF FOSS עבור Python מייצג את מטא-נתוני XMP של מסמך PDF כמודל נתונים בזיכרון שנבנה מ-XmpPacket, XmpField, XmpArray, XmpStruct ו-XmpProperty, כאשר NamespaceProvider פותר קידומות מרחב שמות ל-URI. זה מאפשר לך לקרוא, לבנות ולכתוב מחדש מטא-נתונים מובנים — כותרות, תאריכים, רשימות מילות מפתח, שדות מותאמים אישית — ללא כתיבה ידנית של RDF/XML. הספרייה היא Python טהורה ומותקנת באמצעות הפקודה שלהלן.
מדריך שלב-אחר-שלב
שלב 1: התקנת החבילה
התקן את חבילת Aspose.PDF FOSS:
git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .אמת את ההתקנה על ידי ייבוא XmpPacket והדפסת הודעת אישור:
from aspose_pdf import XmpPacket
print("aspose-pdf-foss-for-python is ready.")שלב 2: ייבא מחלקות נדרשות
ייבא את מחלקות מודל הנתונים של XMP ואת פותר המרחב השמות:
from aspose_pdf import (
NamespaceProvider,
XmpArray,
XmpField,
XmpPacket,
XmpProperty,
XmpStruct,
)שלב 3: צור חבילה והגדר תכונות פשוטות
XmpPacket() מתחיל ברשימת שדות ריקה. set_value(prefix, name, value, uri=...) מגדיר או מחליף תכונה פשוטה, ו-get(prefix_or_uri, name) קורא אותה בחזרה כ-XmpField; get מקבל או את הקידומת הרשומה או את כתובת ה-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"שלב 4: שמור ערכים מסווגים
XmpPacket מספק גישות נוחות מסווגות שממירות אל ולמטה מצורת הטקסט הפשוטה שה-XMP שומר פנימית: set_date/get_date, set_int/get_int, set_real/get_real, ו-set_bool/get_bool. כל מקבל מחזיר None כאשר התכונה חסרה במקום להקפיץ:
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"))שלב 5: שמור טקסט מתורגם ומערכים מסודרים
set_localized_text כותב תכונה חלופית לשפה (rdf:Alt) כגון dc:title בשפה ספציפית, עם ברירת מחדל ל-"x-default". set_array כותב מערך מסודר (Seq), לא-מסודר (Bag) או חלופי (Alt) מרשימה פשוטה של ערכים, ו-get_array קורא אותו בחזרה כרשימת מחרוזות:
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"))שלב 6: בניית ערכים מובנים עם XmpStruct
חלק ממאפייני XMP (רשומות ממד, רשומות היסטוריה) הם ערכים מובנים ולא טקסט פשוט. בנה אחד עם XmpStruct, הוסף אובייקטים של XmpField עם add, וקרא אובייקט בחזרה לפי שם עם get, ואז חבר את המבנה לחבילה עם 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))שלב 7: רישום מרחבי שם XMP מותאמים אישית
NamespaceProvider טעון מראש עם מרחבי השם הסטנדרטיים של XMP (Dublin Core, Adobe XMP, PDF ואחרים). קרא ל-register(prefix, uri) כדי להוסיף מיפוי מותאם — הוא מחזיר את הספק עצמו כך שניתן לשרשר קריאות — ואז חבר את הספק לחבילה כדי שהסיריאליזציה תוכל לפתור את הקידומת המותאמת ל-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")שלב 8: ניתוח וסיריאליזציה של חבילה
XmpPacket.parse(data, provider=...) קורא בתים גולמיים של חבילת XMP או טקסט לתוך XmpPacket. serialize() ו-to_bytes() משחזרים את החבילה חזרה לבתים של חבילת XMP:
xmp_bytes = packet.to_bytes()
restored = XmpPacket.parse(xmp_bytes)
print(restored.get("dc", "title").value)בעיות נפוצות ותיקונים
get() או getter בעל טיפוס מחזיר None למרות שזה עתה הגדרתי את המאפיין
אשר שהארגומנט prefix (או URI) ל-get/get_int/get_date/וכו’ תואם בדיוק למה שהועבר לקריאה המתאימה של set_* — get מתאים הן לקידומת השדה והן ל-URI של מרחב השמות, אך קידומת מותאמת אישית לא תואמת בקריאה אחת ו-URI באחרת תגרום להחמצה.
קידומת מרחב שמות מותאמת אישית מייצרת פלט לא שלם בעת סריאליזציה
קידומת שאינה אחת ממרחבי השמות הסטנדרטיים של XMP (dc, xmp, pdf, וכדומה) דורשת או ארגומנט uri= מפורש בכל קריאה של set_*, או NamespaceProvider שבו קידומת זו רשומה ומצורפת לחבילה דרך XmpPacket(namespace_provider=provider) לפני קריאת serialize()/to_bytes().
get_bool, get_int, או get_real returns None לערך שאני יודע שהוגדר
מחזירי טיפוס אלה מחזירים None כאשר הטקסט השמור אינו מתפרש כסוג הצפוי — לדוגמה, get_int על מאפיין שערכו הוגדר עם set_value כטקסט חופשי במקום set_int. השתמש במגדיר הטיפוס המתאים (set_int, set_real, set_bool) כדי שהלוגיקה של הפענוח במחזיר תתאים לנתיב הכתיבה.
XmpPacket.parse raises ValueError בחבילה ממקור לא מהימן
parse דוחה כל הצהרה של <!DOCTYPE או <!ENTITY כהגנה נגד קלט עוין נגד התקפות XXE והתקפות “billion-laughs”. חבילה חוקית של XMP לעולם אינה זקוקה ל-DTD; התייחס למחרוזת החריגה כסימן שהזרם המקור פגום או לא בטוח במקום לעקוף את ההגנה.
get_array returns None במקום רשימה
get_array מחזיר None כאשר המאפיין המוגדר בשם אינו קיים או לא נשמר כ-XmpArray (לדוגמה, אם הוא הוגדר באמצעות set_value במקום set_array). השתמש ב-set_array בעת כתיבת המאפיין כך שהערך המוגש יתאים לצורה שה-get_array מצפה לה.
שאלות נפוצות
מה ההבדל בין set_value לבין המגדירי טיפוס כמו set_int?
set_value שומר כל מה שאתה מעביר ב-value כפי שהוא. המגדירי טיפוס (set_date, set_int, set_real, set_bool) ממירים את הקלט שלהם לצורת הטקסט הפשוטה שה-XMP משתמש בה פנימית ומשלבים עם מקבל טיפוס תואם שמפענח אותו בחזרה, ולכן השתמש בהם כאשר אתה צריך בטיחות טיפוסית של נסיעה משנית במקום מחרוזות גולמיות.
איך סוגי XmpArray (Bag, Seq, Alt) שונים?
Bag הוא קבוצה בלתי מסודרת של ערכים, Seq היא רשימה מסודרת, ו-Alt מחזיק ערכים חלופיים (בדרך כלל חלופות שפה, כפי שמשתמשים ב-set_localized_text). העבר את הסוג הרצוי ל-set_array(..., kind="Bag") או בנה XmpArray(kind=...) ישירות.
האם אני יכול לקרוא את רשימת המאפיינים הגולמית של חבילה מבלי לדעת את שמותיהם מראש?
כן — עבור על packet.fields, שמחזיק כל XmpField, XmpArray, ו-XmpProperty שנוספו לחבילה בסדר ההוספה.
האם אני צריך NamespaceProvider עבור מרחבי השמות הסטנדרטיים של XMP?
לא. dc, xmp, pdf, והקידומות הסטנדרטיות האחרות נפתרות אוטומטית. NamespaceProvider נדרש רק עבור קידומות מותאמות שאתה ממציא בעצמך.
איך המאפיינים XmpProperty שונים מ-XmpField רגיל?
XmpProperty עוטף XmpField בסיסי יחד עם רשימת שדות מאפיין (המתווספים באמצעות add_qualifier), המשמשת במקרה הפחות נפוץ שבו תכונה עצמה זקוקה למטא-נתוני RDF נוספים המחוברים לערכה, מעבר למאפיין xml:lang ש-XmpField.language כבר מכסה.