مقارنة المستندات
مقارنة المستندات هي عملية تحدد التغييرات بين مستندين وتحتوي على التغييرات كمراجعات. تقوم هذه العملية بمقارنة أي مستندين، بما في ذلك إصدارات مستند واحد محدد، ثم سيتم عرض التغييرات بين المستندين كمراجعات في المستند الأول.
يتم تحقيق طريقة المقارنة من خلال مقارنة الكلمات على مستوى الحرف أو على مستوى الكلمة. إذا كانت الكلمة تحتوي على تغيير حرف واحد على الأقل، فسيتم عرض الفرق في النتيجة كتغيير للكلمة بأكملها، وليس حرفًا. تعتبر عملية المقارنة هذه مهمة معتادة في الصناعات القانونية والمالية.
بدلاً من البحث يدويًا عن الاختلافات بين المستندات أو بين الإصدارات المختلفة منها، يمكنك استخدام Aspose.Words لمقارنة المستندات والحصول على تغييرات المحتوى في التنسيق والرأس/التذييل والجداول والمزيد.
تشرح هذه المقالة كيفية مقارنة المستندات وكيفية تحديد خصائص المقارنة المتقدمة.
حاول عبر الإنترنت
يمكنك مقارنة مستندين عبر الإنترنت باستخدام أداة مقارنة المستندات عبر الإنترنت.
لاحظ أنه يتم استخدام طريقة المقارنة الموضحة أدناه في هذه الأداة لضمان الحصول على نتائج متساوية. لذلك سوف تحصل على نفس النتائج حتى باستخدام أداة المقارنة عبر الإنترنت أو باستخدام طريقة المقارنة في Aspose.Words.
القيود وتنسيقات الملفات المدعومة
تعد مقارنة المستندات ميزة معقدة للغاية. هناك أجزاء متنوعة من مجموعة المحتوى التي تحتاج إلى تحليل للتعرف على جميع الاختلافات. يرجع سبب هذا التعقيد إلى حقيقة أن Aspose.Words يهدف إلى الحصول على نفس نتائج المقارنة مثل خوارزمية مقارنة Microsoft Word.
القيد العام للمستندين اللذين تتم مقارنتهما هو أنه يجب ألا يكون لهما مراجعات قبل استدعاء طريقة المقارنة لأن هذا القيد موجود في Microsoft Word.
قارن بين وثيقتين
عند مقارنة المستندات، تظهر اختلافات المستند الأخير عن الأول كمراجعات للأول. عندما تقوم بتعديل مستند، سيكون لكل تعديل مراجعته الخاصة بعد تشغيل طريقة المقارنة.
يسمح لك Aspose.Words بتحديد الاختلافات في المستندات باستخدام طريقة Compare - وهذا يشبه ميزة مقارنة مستندات Microsoft Word. يتيح لك فحص المستندات أو إصدارات المستندات للعثور على الاختلافات والتغييرات، بما في ذلك تعديلات التنسيق مثل تغييرات الخط وتغييرات التباعد وإضافة الكلمات والفقرات.
ونتيجة للمقارنة، يمكن تحديد المستندات على أنها متساوية أو غير متساوية. يعني مصطلح المستندات “المتساوية” أن طريقة المقارنة غير قادرة على تمثيل التغييرات كمراجعات. وهذا يعني أن نص المستند وتنسيق النص متماثلان. ولكن يمكن أن تكون هناك اختلافات أخرى بين الوثائق. على سبيل المثال، يدعم Microsoft Word مراجعات التنسيق للأنماط فقط، ولا يمكنك تمثيل إدراج/حذف النمط. لذلك يمكن أن تحتوي المستندات على مجموعة مختلفة من الأنماط، ولا تزال طريقة Compare لا تنتج أي مراجعات.
يوضح مثال التعليمات البرمجية التالي كيفية التحقق مما إذا كان المستندان متساويان أم لا:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
Document docA = new Document(dataDir + "TestFile.doc"); | |
Document docB = new Document(dataDir + "TestFile - Copy.doc"); | |
// DocA now contains changes as revisions. | |
docA.Compare(docB, "user", DateTime.Now); | |
if (docA.Revisions.Count == 0) | |
Console.WriteLine("Documents are equal"); | |
else | |
Console.WriteLine("Documents are not equal"); |
يوضح مثال التعليمات البرمجية التالي كيفية تطبيق طريقة Compare
على مستندين ببساطة:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
// The source document doc1. | |
Document doc1 = new Document(); | |
DocumentBuilder builder = new DocumentBuilder(doc1); | |
builder.Writeln("This is the original document."); | |
// The target document doc2. | |
Document doc2 = new Document(); | |
builder = new DocumentBuilder(doc2); | |
builder.Writeln("This is the edited document."); | |
// If either document has a revision, an exception will be thrown. | |
if (doc1.Revisions.Count == 0 && doc2.Revisions.Count == 0) | |
doc1.Compare(doc2, "authorName", DateTime.Now); | |
// If doc1 and doc2 are different, doc1 now has some revisions after the comparison, which can now be viewed and processed. | |
Assert.AreEqual(2, doc1.Revisions.Count); | |
foreach (Revision r in doc1.Revisions) | |
{ | |
Console.WriteLine($"Revision type: {r.RevisionType}, on a node of type \"{r.ParentNode.NodeType}\""); | |
Console.WriteLine($"\tChanged text: \"{r.ParentNode.GetText()}\""); | |
} | |
// All the revisions in doc1 are differences between doc1 and doc2, so accepting them on doc1 transforms doc1 into doc2. | |
doc1.Revisions.AcceptAll(); | |
// doc1, when saved, now resembles doc2. | |
doc1.Save(dataDir + "Document.Compare.docx"); | |
doc1 = new Document(dataDir + "Document.Compare.docx"); | |
Assert.AreEqual(0, doc1.Revisions.Count); | |
Assert.AreEqual(doc2.GetText().Trim(), doc1.GetText().Trim()); |
حدد خيارات المقارنة المتقدمة
هناك العديد من الخصائص المختلفة لفئة CompareOptions والتي يمكنك تطبيقها عندما تريد مقارنة المستندات.
على سبيل المثال، يسمح لك Aspose.Words بتجاهل التغييرات التي تم إجراؤها أثناء عملية المقارنة لأنواع معينة من الكائنات داخل المستند الأصلي. يمكنك تحديد الخاصية المناسبة لنوع الكائن، مثل IgnoreHeadersAndFooters وIgnoreFormatting وIgnoreComments وغيرها عن طريق ضبطها على “true”.
بالإضافة إلى ذلك، يوفر Aspose.Words خاصية Granularity التي يمكنك من خلالها تحديد ما إذا كنت تريد تتبع التغييرات حسب الحرف أو الكلمة.
خاصية شائعة أخرى هي اختيار المستند الذي سيتم عرض تغييرات المقارنة فيه. على سبيل المثال، يحتوي “مربع حوار مقارنة المستندات” في Microsoft Word على خيار “إظهار التغييرات في” - وهذا يؤثر أيضًا على نتائج المقارنة. يوفر Aspose.Words خاصية Target التي تخدم هذا الغرض.
يوضح مثال التعليمات البرمجية التالي كيفية تعيين خصائص المقارنة المتقدمة:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET | |
// Create the original document. | |
Document docOriginal = new Document(); | |
DocumentBuilder builder = new DocumentBuilder(docOriginal); | |
// Insert paragraph text with an endnote. | |
builder.Writeln("Hello world! This is the first paragraph."); | |
builder.InsertFootnote(FootnoteType.Endnote, "Original endnote text."); | |
// Insert a table. | |
builder.StartTable(); | |
builder.InsertCell(); | |
builder.Write("Original cell 1 text"); | |
builder.InsertCell(); | |
builder.Write("Original cell 2 text"); | |
builder.EndTable(); | |
// Insert a textbox. | |
Shape textBox = builder.InsertShape(ShapeType.TextBox, 150, 20); | |
builder.MoveTo(textBox.FirstParagraph); | |
builder.Write("Original textbox contents"); | |
// Insert a DATE field. | |
builder.MoveTo(docOriginal.FirstSection.Body.AppendParagraph("")); | |
builder.InsertField(" DATE "); | |
// Insert a comment. | |
Comment newComment = new Comment(docOriginal, "John Doe", "J.D.", DateTime.Now); | |
newComment.SetText("Original comment."); | |
builder.CurrentParagraph.AppendChild(newComment); | |
// Insert a header. | |
builder.MoveToHeaderFooter(HeaderFooterType.HeaderPrimary); | |
builder.Writeln("Original header contents."); | |
// Create a clone of our document, which we will edit and later compare to the original. | |
Document docEdited = (Document)docOriginal.Clone(true); | |
Paragraph firstParagraph = docEdited.FirstSection.Body.FirstParagraph; | |
// Change the formatting of the first paragraph, change casing of original characters and add text. | |
firstParagraph.Runs[0].Text = "hello world! this is the first paragraph, after editing."; | |
firstParagraph.ParagraphFormat.Style = docEdited.Styles[StyleIdentifier.Heading1]; | |
// Edit the footnote. | |
Footnote footnote = (Footnote)docEdited.GetChild(NodeType.Footnote, 0, true); | |
footnote.FirstParagraph.Runs[1].Text = "Edited endnote text."; | |
// Edit the table. | |
Table table = (Table)docEdited.GetChild(NodeType.Table, 0, true); | |
table.FirstRow.Cells[1].FirstParagraph.Runs[0].Text = "Edited Cell 2 contents"; | |
// Edit the textbox. | |
textBox = (Shape)docEdited.GetChild(NodeType.Shape, 0, true); | |
textBox.FirstParagraph.Runs[0].Text = "Edited textbox contents"; | |
// Edit the DATE field. | |
FieldDate fieldDate = (FieldDate)docEdited.Range.Fields[0]; | |
fieldDate.UseLunarCalendar = true; | |
// Edit the comment. | |
Comment comment = (Comment)docEdited.GetChild(NodeType.Comment, 0, true); | |
comment.FirstParagraph.Runs[0].Text = "Edited comment."; | |
// Edit the header. | |
docEdited.FirstSection.HeadersFooters[HeaderFooterType.HeaderPrimary].FirstParagraph.Runs[0].Text = "Edited header contents."; | |
// Apply different comparing options. | |
CompareOptions compareOptions = new CompareOptions(); | |
compareOptions.IgnoreFormatting = false; | |
compareOptions.IgnoreCaseChanges = false; | |
compareOptions.IgnoreComments = false; | |
compareOptions.IgnoreTables = false; | |
compareOptions.IgnoreFields = false; | |
compareOptions.IgnoreFootnotes = false; | |
compareOptions.IgnoreTextboxes = false; | |
compareOptions.IgnoreHeadersAndFooters = false; | |
compareOptions.Target = ComparisonTargetType.New; | |
// compare both documents. | |
docOriginal.Compare(docEdited, "John Doe", DateTime.Now, compareOptions); | |
docOriginal.Save(dataDir + "Document.CompareOptions.docx"); | |
docOriginal = new Document(dataDir + "Document.CompareOptions.docx"); | |
// If you set compareOptions to ignore certain types of changes, | |
// then revisions done on those types of nodes will not appear in the output document. | |
// You can tell what kind of node a revision was done on by looking at the NodeType of the revision's parent nodes. | |
Assert.AreNotEqual(compareOptions.IgnoreFormatting, docOriginal.Revisions.Any(rev => rev.RevisionType == RevisionType.FormatChange)); | |
Assert.AreNotEqual(compareOptions.IgnoreCaseChanges, docOriginal.Revisions.Any(s => s.ParentNode.GetText().Contains("hello"))); | |
Assert.AreNotEqual(compareOptions.IgnoreComments, docOriginal.Revisions.Any(rev => HasParentOfType(rev, NodeType.Comment))); | |
Assert.AreNotEqual(compareOptions.IgnoreTables, docOriginal.Revisions.Any(rev => HasParentOfType(rev, NodeType.Table))); | |
Assert.AreNotEqual(compareOptions.IgnoreFields, docOriginal.Revisions.Any(rev => HasParentOfType(rev, NodeType.FieldStart))); | |
Assert.AreNotEqual(compareOptions.IgnoreFootnotes, docOriginal.Revisions.Any(rev => HasParentOfType(rev, NodeType.Footnote))); | |
Assert.AreNotEqual(compareOptions.IgnoreTextboxes, docOriginal.Revisions.Any(rev => HasParentOfType(rev, NodeType.Shape))); | |
Assert.AreNotEqual(compareOptions.IgnoreHeadersAndFooters, docOriginal.Revisions.Any(rev => HasParentOfType(rev, NodeType.HeaderFooter))); |