比較文件

比較文件是一個過程,它會識別出兩份文件之間的改變,並把改變記錄下來作為修訂版。 這個過程會將任何兩份文件進行比較,包括某份特定文件的不同版本,然後顯示出這兩份文件之間的改變,這些變化會在第一份文件中呈現。

比對方法是透過字元或字詞層級進行比較達到。 若一個字中至少有一個字元的變化,在結果中該差異會顯示為整個字元的改變,而非單個字元的變化。 這個比較過程是在法律與金融產業中常見的任務。

而不是手動地尋找文件之間的差異或他們不同的版本,你可以用 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讓你可以在原始文件中比較某些類型的物件時忽略所做的變更。 您可以為物件類型選擇適當的屬性,例如 IgnoreHeadersAndFootersIgnoreFormattingIgnoreComments 等,或設定為 "" 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)));