💡 דוגמה מלאה עובדת זמינה ב‑GitHub:
extract-annotations-from-pdf-using-groupdocs-parser-dotnet
מבוא
קובץ PDF שעבר ביקורת בדרך כלל מכיל יותר מהטקסט הגלוי שלו – פתקים דביקים, הערות מודגשות, והערות משולבות שהשאירו הסוקרים. גלילה בכל דף כדי למצוא אותן אינה ניתנת להרחבה ברגע שהמסמך עבר כמה סבבי משוב. GroupDocs.Parser היא ספריית .NET שקוראת את ההערות המוטמעות במסמך באופן תכנותי, וממירה את ההערות המפוזרות של הסוקרים לנתונים מובנים שהקוד שלך יכול לפעול עליהם. מדריך זה מראה כיצד לחלץ הערות מכל קובץ PDF, לפרק אותן דף‑דף, לשלב אותן עם הטקסט של המסמך, ולייצא את התוצאות ל‑CSV או JSON.
נתקלתי בבעיה זו בזמן בניית עוקב ביקורות לצוות תיעוד: מסמך שחרור של 40 דפים עבר שלושה סוקרים, והפתיחה הידנית של הקובץ כדי למצוא כל תגובה לקחה יותר זמן מאשר לתקן את הבעיות שסומנו. חילוץ ההערות בכמה שורות קוד הפך זאת למשימה של שתי דקות.
בקטעים הבאים תלמדו כיצד:
- לחלץ כל הערה מ‑PDF בפעם אחת.
- לתייג כל הערה עם הדף שאליו היא שייכת.
- לשלב את טקסט המסמך וטקסט ההערה יחד בקריאה אחת.
- לסריאליזציה של התוצאות ל‑CSV או JSON לכלים משניים.
למה חילוץ הערות PDF חשוב
קריאת הערות PDF באופן תכנותי שימושית עבור:
- תהליכי ביקורת: איסוף כל תגובת הסוקר ללא פתיחת הקובץ בתצוגת PDF.
- שיתוף פעולה: הצגת קטעים מודגשים או מוסתרים ישירות בתוך הכלים שלכם.
- ביקורת: שמירת רישום של סימונים שהושארו על המסמך לאורך זמן, גם לאחר שהמסמך שטוח או סופי.
GroupDocs.Parser הוסיפה חילוץ ערות מובנה למסמכי PDF בגרסה 26.7 דרך המתודה GetAnnotations, יחד עם אפשרות חדשה IncludeAnnotations ב‑TextOptions לשילוב טקסט ההערה בקריאת טקסט רגילה.
דרישות מוקדמות
- .NET 6.0 או גרסה מאוחרת יותר
- GroupDocs.Parser for .NET 26.7+ (רישיון זמני)
- קובץ PDF עם הערות קיימות (למשל,
document-with-annotations.pdf)
התקנה דרך NuGet:
dotnet add package GroupDocs.Parser
איך לחלץ הערות מקובץ PDF?
תשובה: טען את הקובץ עם Parser, ואז קרא GetAnnotations() לכל המסמך או GetAnnotations(pageIndex) לדף בודד. כל תוצאה היא אוסף של אובייקטים מסוג AnnotationItem שהמאפיין Value שלו מכיל את טקסט ההערה. אם אתה מעדיף לראות את ההערות משולבות עם תוכן המסמך הרגיל, הגדר IncludeAnnotations ב‑TextOptions וקרא GetText במקום זאת.
חילוץ לכל המסמך
הקטע הבא מושך כל ההערה מהקובץ בקריאה אחת, שהיא הדרך המהירה ביותר לבדוק אם למסמך יש תגובות פתוחות בכלל.
// Extract every annotation from the whole document
var result = new List<string>();
using (var parser = new Parser(path))
{
IEnumerable<AnnotationItem> annotations = parser.GetAnnotations();
if (annotations == null)
{
return result; // format doesn't support annotations
}
foreach (var item in annotations)
{
result.Add(item.Value); // annotation text
}
}
return result;
נקודות מפתח:
GetAnnotations()מחזירהnullכאשר חילוץ הערות אינו נתמך עבור המסמך, ואוסף ריק כאשר למסמך פשוט אין הערות.- כל
AnnotationItemחושף את הטקסט שלו דרך המאפייןValue– זהו הנתון היחיד שה‑SDK מדווח עליו כיום. - כאן לא נכללת שיוך לדף; השתמש בגרסת העומס לדף למטה אם אתה צריך זאת.
חילוץ לפי דף
כאשר מיקום ההערה חשוב, חזור על דפי המסמך וקרא GetAnnotations(pageIndex) עבור כל אחד מהם.
// Tag each annotation with its zero-based page index
var result = new List<AnnotationRecord>();
using (var parser = new Parser(path))
{
if (!parser.Features.Annotations)
{
return result;
}
var info = parser.GetDocumentInfo();
if (info == null || info.PageCount == 0)
{
return result;
}
for (int pageIndex = 0; pageIndex < info.PageCount; pageIndex++)
{
IEnumerable<AnnotationItem> pageAnnotations = parser.GetAnnotations(pageIndex);
if (pageAnnotations == null)
{
continue;
}
foreach (var item in pageAnnotations)
{
result.Add(new AnnotationRecord { PageIndex = pageIndex, Value = item.Value });
}
}
}
return result;
נקודות מפתח:
GetDocumentInfo().PageCountמניע את הלולאה; אין “ספירת דפי הערות” נפרדת.GetAnnotations(pageIndex)משתמש במפתח אפס‑מבוסס, כמו כל שיטה אחרת ברמת דף ב‑API.- רשימת
AnnotationRecordהמתקבלת היא בדיוק הצורה שהייצוא ל‑CSV או JSON דורש.
חילוץ טקסט יחד עם הערות
במקום שני מעברים על המסמך, ניתן לשלב את טקסט ההערה ישירות בפלט של חילוץ הטקסט הרגיל.
// Read document text with annotation text included
using (var parser = new Parser(path))
{
var options = new TextOptions
{
IncludeAnnotations = true
};
using (TextReader reader = parser.GetText(options))
{
return reader?.ReadToEnd() ?? string.Empty;
}
}
נקודות מפתח:
IncludeAnnotationsהוא מאפיין ב‑TextOptions, ולכן זה עובד עם קריאתGetTextאותה השתמשת כבר לחילוץ טקסט רגיל.- שימושי כאשר אתה רוצה פלט יחיד בסגנון תמליל במקום רשימת תגובות נפרדת.
- ניתן לשלב עם
GetText(pageIndex, options)אם אתה צריך זאת רק לדף אחד.
בדיקת תמיכת הערות מראש
לא כל פורמט תומך בהערות, ולכן כדאי לבדוק לפני שמבנים לוגיקה סביב GetAnnotations.
// Returns true if the loaded document format supports annotation extraction
using (var parser = new Parser(path))
{
return parser.Features.Annotations;
}
נקודות מפתח:
Features.Annotationsהוא דגל בוליאני פשוט על מופע ה‑Parser.- בדיקה מראש עושה את הכוונה ברורה, למרות ש‑
GetAnnotationsכבר מחזירהnullבצורה אלגנטית.
ייצוא ההערות ל‑CSV
ייצוא ל‑CSV מאפשר לסוקרים לפתוח את רשימת ההערות ישירות באקסל. המתודה שלהלן כותבת קובץ דו‑עמודי (page,value) מהרשומות המתויגות לפי דף שנבנו קודם.
var sb = new StringBuilder();
sb.AppendLine("page,value");
foreach (var record in records)
{
sb.AppendLine($"{record.PageIndex},{CsvEscape(record.Value)}");
}
File.WriteAllText(outputPath, sb.ToString());
נקודות מפתח:
CsvEscapeמציטט באופן בטוח שדות המכילים פסיקים, מרכאות או שורות חדשות.- הקובץ המתקבל נפתח ישירות באקסל או ניתן להעבירו לכלי ניהול תקלות.
עזר: CsvEscape
if (string.IsNullOrEmpty(s)) return string.Empty;
if (s.Contains(",") || s.Contains("\"") || s.Contains("\n"))
{
return "\"" + s.Replace("\"", "\"\"") + "\"";
}
return s;
ייצוא ההערות ל‑JSON
לצינורות שמצריכים תגובות באופן תכנותי, מערך JSON הוא בדרך כלל בחירה מתאימה יותר מאשר CSV שטוח.
var sb = new StringBuilder();
sb.AppendLine("[");
for (int i = 0; i < records.Count; i++)
{
var comma = i < records.Count - 1 ? "," : string.Empty;
sb.AppendLine($" {{ \"page\": {records[i].PageIndex}, \"value\": \"{Escape(records[i].Value)}\" }}{comma}");
}
sb.AppendLine("]");
File.WriteAllText(outputPath, sb.ToString());
נקודות מפתח:
- הפלט הוא מערך שטוח של אובייקטים
{ page, value }– קל לדסיריאליזציה על ידי כל שירות משני. Escapeשומר על תקינות ה‑JSON מבלי להוסיף ספריית סריאליזציה.
עזר: Escape
return s?.Replace("\\", "\\\\").Replace("\"", "\\\"") ?? string.Empty;
השוואת שיטות: מתי להשתמש בכל אחת
| שיטה | מתאים ל‑ | יתרונות מרכזיים | מגבלות |
|---|---|---|---|
| חילוץ לכל המסמך | בדיקה מהירה של “האם יש תגובות בכלל?” | קריאה אחת, קוד פשוט | אין שיוך לדף |
| חילוץ לפי דף | ניתוב משוב לחלק הנכון | תוצאות מתויגות בדף, מוכנות לייצוא | קריאה נוספת לכל דף |
| טקסט משולב + הערות | תמליל קריא יחיד | אין צורך במעבר שני על המסמך | ההערות אינן מופרדות מטקסט הגוף |
| ייצוא CSV | מעקב ביקורות מבוסס גיליון | פתיחה קלה באקסל, קריא לבני אדם | מוגבל למבנה שטוח |
| ייצוא JSON | צינורות אוטומטיים, מערכות ניהול תקלות | מובנה, קריא למכונה | משקל פayload מעט גדול יותר |
התחל עם חילוץ לכל המסמך כדי לאשר שלקובץ יש תגובות שמצריכות טיפול, ואז עבור לחילוץ לפי דף כאשר אתה צריך לנתב משוב לחלק ספציפי.
שיטות עבודה מומלצות וטיפים
- שחרור
Parserמיידית: עטוף אותו ב‑usingכדי לשחרר משאבים מקומיים. - הבחנה בין
nullלריק:GetAnnotationsהמחזירהnullמשמעותה שהפורמט אינו נתמך; אוסף ריק משמעותו שאין למסמך הערות. - בדוק
Features.Annotationsבעבודות אצווה: דלג על קבצים לא נתמכים מוקדם במקום להסתמך על בדיקתnullעמוקה בלולאה. - השתמש ברשימת הדפים המתויגת פעם אחת: בנה אותה עם
ExtractAnnotationsByPageוהזין את שני המייצאים (CSV ו‑JSON) מאותו מקור, כך שהפלטים לעולם לא יתפצלו. - אבטחה: טקסט ההערה הוא קלט חופשי של הסוקר – התייחס אליו כמו לכל מחרוזת לא מהימנה לפני הצגתו בממשק משתמש או בדוח.
סיכום
GroupDocs.Parser מספקת דרך ישירה ותכנותית לחלץ תגובות סוקרים מתוך PDF במקום לחפש אותן ידנית. על‑ידי חילוץ הערות לכל המסמך, תיוגן לפי דף, או שילובן עם זרם הטקסט הרגיל, ניתן לבנות תהליכי ביקורת שמציגים משוב ברגע שהמסמך נכנס לצינור העבודה שלכם. ייצא את התוצאות ל‑CSV או JSON וחבר אותן ישירות לכלים שהצוות שלכם כבר משתמש בהם.
צעדים הבאים:
- חקור את תיעוד API של GetAnnotations לקבלת החתימה המלאה של המתודה והעמסתה.
- למד כיצד לחלץ טקסט ממסמכי PDF יחד עם הערות לצורך צינור תוכן שלם.
- עיין בפרויקטים לדוגמא נוספים ב‑GitHub לתרחישי עיבוד אצווה (מאגר דוגמאות).