- Fix for "Format matching in ReplaceText does not work properly" - New method: RemoveTextInGivenFormat - Added unit test: Test_Paragraph_ReplaceTextInGivenFormat - Added 'VariousTextFormatting.docx' file for unit testing purposes - Moved ContainsEveryChildOf method to HelperFunction becasue it is shared by Contaner and Paragraph - Added new feature in Container class: RemoveTextInGivenFormat - Added unit test: Test_Document_RemoveTextInGivenFormatmaster
| @@ -427,6 +427,41 @@ namespace Novacode | |||
| p.ReplaceText(oldValue, newValue, trackChanges, options, newFormatting, matchFormatting, fo); | |||
| } | |||
| /// <summary> | |||
| /// Removes all items with required formatting | |||
| /// </summary> | |||
| /// <returns>Numer of texts removed</returns> | |||
| public int RemoveTextInGivenFormat(Formatting matchFormatting, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch) | |||
| { | |||
| var deletedCount = 0; | |||
| foreach (var x in Xml.Elements()) | |||
| { | |||
| deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo); | |||
| } | |||
| return deletedCount; | |||
| } | |||
| internal int RemoveTextWithFormatRecursive(XElement element, Formatting matchFormatting, MatchFormattingOptions fo) | |||
| { | |||
| var deletedCount = 0; | |||
| foreach (var x in element.Elements()) | |||
| { | |||
| if ("rPr".Equals(x.Name.LocalName)) | |||
| { | |||
| if (HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, x, fo)) | |||
| { | |||
| x.Parent.Remove(); | |||
| ++deletedCount; | |||
| } | |||
| } | |||
| deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo); | |||
| } | |||
| return deletedCount; | |||
| } | |||
| public virtual void InsertAtBookmark(string toInsert, string bookmarkName) | |||
| { | |||
| if (String.IsNullOrWhiteSpace(bookmarkName)) | |||
| @@ -15,6 +15,29 @@ namespace Novacode | |||
| { | |||
| internal static class HelperFunctions | |||
| { | |||
| /// <summary> | |||
| /// Checks whether 'toCheck' has all children that 'desired' has and values of 'val' attributes are the same | |||
| /// </summary> | |||
| /// <param name="desired"></param> | |||
| /// <param name="toCheck"></param> | |||
| /// <param name="fo">Matching options whether check if desired attributes are inder a, or a has exactly and only these attributes as b has.</param> | |||
| /// <returns></returns> | |||
| internal static bool ContainsEveryChildOf(XElement desired, XElement toCheck, MatchFormattingOptions fo) | |||
| { | |||
| foreach (XElement e in desired.Elements()) | |||
| { | |||
| // If a formatting property has the same name and 'val' attribute's value, its considered to be equivalent. | |||
| if (!toCheck.Elements(e.Name).Where(bElement => bElement.GetAttribute(XName.Get("val", DocX.w.NamespaceName)) == e.GetAttribute(XName.Get("val", DocX.w.NamespaceName))).Any()) | |||
| return false; | |||
| } | |||
| // If the formatting has to be exact, no additionaly formatting must exist. | |||
| if (fo == MatchFormattingOptions.ExactMatch) | |||
| return desired.Elements().Count() == toCheck.Elements().Count(); | |||
| return true; | |||
| } | |||
| internal static void CreateRelsPackagePart(DocX Document, Uri uri) | |||
| { | |||
| PackagePart pp = Document.package.CreatePart(uri, "application/vnd.openxmlformats-package.relationships+xml", CompressionOption.Maximum); | |||
| @@ -3642,7 +3642,7 @@ namespace Novacode | |||
| * Make sure that every formatting element in f.xml is also in this run, | |||
| * if this is not true, then their formatting does not match. | |||
| */ | |||
| if (!ContainsEveryChildOf(matchFormatting.Xml, rPr, fo)) | |||
| if (!HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, rPr, fo)) | |||
| { | |||
| formattingMatch = false; | |||
| break; | |||
| @@ -3663,22 +3663,6 @@ namespace Novacode | |||
| } | |||
| } | |||
| internal bool ContainsEveryChildOf(XElement a, XElement b, MatchFormattingOptions fo) | |||
| { | |||
| foreach (XElement e in a.Elements()) | |||
| { | |||
| // If a formatting property has the same name and value, its considered to be equivalent. | |||
| if (!b.Elements(e.Name).Where(bElement => bElement.Value == e.Value).Any()) | |||
| return false; | |||
| } | |||
| // If the formatting has to be exact, no additionaly formatting must exist. | |||
| if (fo == MatchFormattingOptions.ExactMatch) | |||
| return a.Elements().Count() == b.Elements().Count(); | |||
| return true; | |||
| } | |||
| /// <summary> | |||
| /// Find all instances of a string in this paragraph and return their indexes in a List. | |||
| /// </summary> | |||
| @@ -926,6 +926,59 @@ namespace UnitTests | |||
| } | |||
| } | |||
| [TestMethod] | |||
| public void Test_Paragraph_ReplaceTextInGivenFormat() | |||
| { | |||
| // Load a document. | |||
| using (DocX document = DocX.Load(_directoryWithFiles + "VariousTextFormatting.docx")) | |||
| { | |||
| // Removing red text highlighted with yellow | |||
| var formatting = new Formatting(); | |||
| formatting.FontColor = Color.Blue; | |||
| // IMPORTANT: default constructor of Formatting sets up language property - set it to NULL to be language independent | |||
| var desiredFormat = new Formatting() { Language = null, FontColor = Color.FromArgb(255, 0, 0), Highlight = Highlight.yellow }; | |||
| var replaced = string.Empty; | |||
| foreach (var p in document.Paragraphs) | |||
| { | |||
| if (p.Text == "Text highlighted with yellow") | |||
| { | |||
| p.ReplaceText("Text highlighted with yellow", "New text highlighted with yellow", false, RegexOptions.None, null, desiredFormat, MatchFormattingOptions.ExactMatch); | |||
| replaced += p.Text; | |||
| } | |||
| } | |||
| Assert.AreEqual("New text highlighted with yellow", replaced); | |||
| // Removing red text with no other formatting (ExactMatch) | |||
| desiredFormat = new Formatting() { Language = null, FontColor = Color.FromArgb(255, 0, 0) }; | |||
| var count = 0; | |||
| foreach (var p in document.Paragraphs) | |||
| { | |||
| p.ReplaceText("Text", "Replaced text", false, RegexOptions.None, null, desiredFormat, MatchFormattingOptions.ExactMatch); | |||
| if (p.Text.StartsWith("Replaced text")) | |||
| { | |||
| ++count; | |||
| } | |||
| } | |||
| Assert.AreEqual(1, count); | |||
| // Removing just red text with any other formatting (SubsetMatch) | |||
| desiredFormat = new Formatting() { Language = null, FontColor = Color.FromArgb(255, 0, 0) }; | |||
| count = 0; | |||
| foreach (var p in document.Paragraphs) | |||
| { | |||
| p.ReplaceText("Text", "Replaced text", false, RegexOptions.None, null, desiredFormat, MatchFormattingOptions.SubsetMatch); | |||
| if (p.Text.StartsWith("Replaced text")) | |||
| { | |||
| ++count; | |||
| } | |||
| } | |||
| Assert.AreEqual(2, count); | |||
| } | |||
| } | |||
| [TestMethod] | |||
| public void Test_Paragraph_RemoveText() | |||
| { | |||
| @@ -1037,6 +1090,30 @@ namespace UnitTests | |||
| } | |||
| } | |||
| [TestMethod] | |||
| public void Test_Document_RemoveTextInGivenFormat() | |||
| { | |||
| // Load a document. | |||
| using (DocX document = DocX.Load(_directoryWithFiles + "VariousTextFormatting.docx")) | |||
| { | |||
| var formatting = new Formatting(); | |||
| formatting.FontColor = Color.Blue; | |||
| // IMPORTANT: default constructor of Formatting sets up language property - set it to NULL to be language independent | |||
| formatting.Language = null; | |||
| var deletedCount = document.RemoveTextInGivenFormat(formatting); | |||
| Assert.AreEqual(2, deletedCount); | |||
| deletedCount = document.RemoveTextInGivenFormat(new Formatting() { Highlight = Highlight.yellow, Language = null }); | |||
| Assert.AreEqual(2, deletedCount); | |||
| deletedCount = document.RemoveTextInGivenFormat(new Formatting() { Highlight = Highlight.blue, Language = null, FontColor = Color.FromArgb(0, 255, 0) }); | |||
| Assert.AreEqual(1, deletedCount); | |||
| deletedCount = document.RemoveTextInGivenFormat(new Formatting() { Language = null, FontColor = Color.FromArgb(123, 123, 123) }, MatchFormattingOptions.ExactMatch); | |||
| Assert.AreEqual(2, deletedCount); | |||
| } | |||
| } | |||
| [TestMethod] | |||
| public void Test_Paragraph_InsertText() | |||
| { | |||
| @@ -90,6 +90,7 @@ | |||
| <None Include="documents\testdoc_SectionsWithSectionBreaksMultiParagraph.docx" /> | |||
| <None Include="documents\testdoc_UnorderedList.docx" /> | |||
| <None Include="documents\TestParent.docx" /> | |||
| <None Include="documents\VariousTextFormatting.docx" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Content Include="documents\green.jpg" /> | |||