วิธีทำงานกับข้อมูล 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) เพื่อเพิ่มการแมปแบบกำหนดเอง — มันจะคืนค่า provider ตัวเองเพื่อให้สามารถเชื่อมต่อการเรียกต่อกันได้ — จากนั้นผูก provider เข้ากับแพ็กเก็ตเพื่อให้การซีเรียลไลซ์สามารถแก้ไขคำนำหน้าที่กำหนดเองให้เป็น 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/etc. ตรงกับสิ่งที่ส่งให้กับการเรียก 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 สำหรับค่าที่ฉันรู้ว่าได้ตั้งไว้
getter ที่ระบุประเภทเหล่านี้จะคืนค่า None เมื่อข้อความที่เก็บไว้ไม่สามารถแปลงเป็นประเภทที่คาดหวัง — ตัวอย่างเช่น, get_int บนคุณสมบัติที่ค่าถูกตั้งด้วย set_value เป็นข้อความอิสระแทน set_int. ใช้ setter ที่สอดคล้องกัน (set_int, set_real, set_bool) เพื่อให้ตรรกะการแปลงของ getter ตรงกับเส้นทางการเขียน.
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 ครอบคลุมอยู่แล้ว.