قارن المستندات

مقارنة المستندات هي عملية تحدد التغييرات بين وثيقتين وتحتوي على التغييرات كمراجعات. تقارن هذه العملية أي وثيقتين، بما في ذلك إصدارات مستند واحد محدد، ثم سيتم عرض التغييرات بين كلتا الوثيقتين كمراجعات في المستند الأول.

يتم تحقيق طريقة المقارنة من خلال مقارنة الكلمات على مستوى الحرف أو مستوى الكلمة. إذا كانت الكلمة تحتوي على تغيير حرف واحد على الأقل، في النتيجة، سيتم عرض الفرق كتغيير للكلمة بأكملها، وليس حرفا. عملية المقارنة هذه هي مهمة معتادة في الصناعات القانونية والمالية.

بدلا من البحث يدويا عن الاختلافات بين المستندات أو بين الإصدارات المختلفة منها، يمكنك استخدام 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-C
System::SharedPtr<Document> docA = System::MakeObject<Document>(inputDataDir + u"TestFile.doc");
System::SharedPtr<Document> docB = System::MakeObject<Document>(inputDataDir + u"TestFile - Copy.doc");
// DocA now contains changes as revisions.
docA->Compare(docB, u"user", System::DateTime::get_Now());
if (docA->get_Revisions()->get_Count() == 0)
{
std::cout << "Documents are equal" << std::endl;
}
else
{
std::cout << "Documents are not equal" << std::endl;
}

يوضح مثال الكود التالي كيفية تطبيق طريقة Compare ببساطة على وثيقتين:

For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C
// The source document doc1
System::SharedPtr<Document> doc1 = System::MakeObject<Document>();
System::SharedPtr<DocumentBuilder> builder = System::MakeObject<DocumentBuilder>(doc1);
builder->Writeln(u"This is the original document.");
// The target document doc2
System::SharedPtr<Document> doc2 = System::MakeObject<Document>();
builder = System::MakeObject<DocumentBuilder>(doc2);
builder->Writeln(u"This is the edited document.");
// If either document has a revision, an exception will be thrown
if (doc1->get_Revisions()->get_Count() == 0 && doc2->get_Revisions()->get_Count() == 0)
doc1->Compare(doc2, u"authorName", System::DateTime::get_Now());
// If doc1 and doc2 are different, doc1 now has some revisions after the comparison, which can now be viewed and processed
if (doc1->get_Revisions()->get_Count() == 2)
std::cout << "Documents are equal." << std::endl << std::endl;
for (System::SharedPtr<Revision> r : System::IterateOver(doc1->get_Revisions()))
{
std::cout << "Revision type: " << System::ObjectExt::ToString(r->get_RevisionType()).ToUtf8String()
<< ", on a node of type " << System::ObjectExt::ToString(r->get_ParentNode()->get_NodeType()).ToUtf8String() << std::endl;
std::cout << "Changed text: " << r->get_ParentNode()->GetText() << std::endl;
}
// All the revisions in doc1 are differences between doc1 and doc2, so accepting them on doc1 transforms doc1 into doc2
doc1->get_Revisions()->AcceptAll();
// doc1, when saved, now resembles doc2
doc1->Save(inputDataDir + u"Document.Compare.docx");
doc1 = System::MakeObject<Document>(inputDataDir + u"Document.Compare.docx");
if (doc1->get_Revisions()->get_Count() == 0)
std::cout << "Documents are equal" << std::endl;
if (doc2->GetText().Trim() == doc1->GetText().Trim())
std::cout << "Documents are equal" << std::endl;

حدد خيارات المقارنة المتقدمة

هناك العديد من الخصائص المختلفة لفئة CompareOptions التي يمكنك تطبيقها عندما تريد مقارنة المستندات.

على سبيل المثال، Aspose.Words يسمح لك بتجاهل التغييرات التي تم إجراؤها أثناء عملية المقارنة لأنواع معينة من الكائنات داخل المستند الأصلي. يمكنك تحديد الخاصية المناسبة لنوع الكائن، مثل IgnoreHeadersAndFooters, IgnoreFormatting, IgnoreComments, وغيرها من خلال وضع لهم “صحيح”.

بالإضافة إلى ذلك، يوفر 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-C
// Create the original document
System::SharedPtr<Document> docOriginal = System::MakeObject<Document>();
System::SharedPtr<DocumentBuilder> builder = System::MakeObject<DocumentBuilder>(docOriginal);
// Insert paragraph text with an endnote
builder->Writeln(u"Hello world! This is the first paragraph.");
builder->InsertFootnote(FootnoteType::Endnote, u"Original endnote text.");
// Insert a table
builder->StartTable();
builder->InsertCell();
builder->Write(u"Original cell 1 text");
builder->InsertCell();
builder->Write(u"Original cell 2 text");
builder->EndTable();
// Insert a textbox
System::SharedPtr<Shape> textBox = builder->InsertShape(ShapeType::TextBox, 150, 20);
builder->MoveTo(textBox->get_FirstParagraph());
builder->Write(u"Original textbox contents");
// Insert a DATE field
builder->MoveTo(docOriginal->get_FirstSection()->get_Body()->AppendParagraph(u""));
builder->InsertField(u" DATE ");
// Insert a comment
auto newComment = System::MakeObject<Comment>(docOriginal, u"John Doe", u"J.D.", System::DateTime::get_Now());
newComment->SetText(u"Original comment.");
builder->get_CurrentParagraph()->AppendChild(newComment);
// Insert a header
builder->MoveToHeaderFooter(Aspose::Words::HeaderFooterType::HeaderPrimary);
builder->Writeln(u"Original header contents.");
// Create a clone of our document, which we will edit and later compare to the original
auto docEdited = System::DynamicCast<Aspose::Words::Document>(System::StaticCast<Node>(docOriginal)->Clone(true));
System::SharedPtr<Paragraph> firstParagraph = docEdited->get_FirstSection()->get_Body()->get_FirstParagraph();
// Change the formatting of the first paragraph, change casing of original characters and add text
firstParagraph->get_Runs()->idx_get(0)->set_Text(u"hello world! this is the first paragraph, after editing.");
firstParagraph->get_ParagraphFormat()->set_Style(docEdited->get_Styles()->idx_get(Aspose::Words::StyleIdentifier::Heading1));
// Edit the footnote
auto footnote = System::DynamicCast<Aspose::Words::Footnote>(docEdited->GetChild(Aspose::Words::NodeType::Footnote, 0, true));
footnote->get_FirstParagraph()->get_Runs()->idx_get(1)->set_Text(u"Edited endnote text.");
// Edit the table
auto table = System::DynamicCast<Aspose::Words::Tables::Table>(docEdited->GetChild(Aspose::Words::NodeType::Table, 0, true));
table->get_FirstRow()->get_Cells()->idx_get(1)->get_FirstParagraph()->get_Runs()->idx_get(0)->set_Text(u"Edited Cell 2 contents");
// Edit the textbox
textBox = System::DynamicCast<Aspose::Words::Drawing::Shape>(docEdited->GetChild(Aspose::Words::NodeType::Shape, 0, true));
textBox->get_FirstParagraph()->get_Runs()->idx_get(0)->set_Text(u"Edited textbox contents");
// Edit the DATE field
auto fieldDate = System::DynamicCast<Aspose::Words::Fields::FieldDate>(docEdited->get_Range()->get_Fields()->idx_get(0));
fieldDate->set_UseLunarCalendar(true);
// Edit the comment
auto comment = System::DynamicCast<Aspose::Words::Comment>(docEdited->GetChild(Aspose::Words::NodeType::Comment, 0, true));
comment->get_FirstParagraph()->get_Runs()->idx_get(0)->set_Text(u"Edited comment.");
// Edit the header
docEdited->get_FirstSection()->get_HeadersFooters()->idx_get(Aspose::Words::HeaderFooterType::HeaderPrimary)->get_FirstParagraph()->get_Runs()->idx_get(0)->set_Text(u"Edited header contents.");
// When we compare documents, the differences of the latter document from the former show up as revisions to the former
// Each edit that we've made above will have its own revision, after we run the Compare method
// We can compare with a CompareOptions object, which can suppress changes done to certain types of objects within the original document
// from registering as revisions after the comparison by setting some of these members to "true"
auto compareOptions = System::MakeObject<Aspose::Words::CompareOptions>();
compareOptions->set_IgnoreFormatting(false);
compareOptions->set_IgnoreCaseChanges(false);
compareOptions->set_IgnoreComments(false);
compareOptions->set_IgnoreTables(false);
compareOptions->set_IgnoreFields(false);
compareOptions->set_IgnoreFootnotes(false);
compareOptions->set_IgnoreTextboxes(false);
compareOptions->set_IgnoreHeadersAndFooters(false);
compareOptions->set_Target(Aspose::Words::ComparisonTargetType::New);
docOriginal->Compare(docEdited, u"John Doe", System::DateTime::get_Now(), compareOptions);
docOriginal->Save(inputDataDir + u"Document.CompareOptions.docx");