Syncfusion DocIO Replace Text with merge Field - c#

I have a whole bunch of document which have a plain text place marker like ~{fieldToBeReplaced} and I want it to be replaced with a Merge field.
I have the following code which kind of inserts the merge field and then inserts the text << MERGEFIELD_NAME >>.
What I want is it to be the mergefield with the name displayed just like it would be if i were to Insert->Merge Field in word.
//linqPad Script
void Main()
{
Console.WriteLine("::::: Replacing BookMarks ::::: ");
//Search And Replace bookmarks
try
{
var replaceDir = new DirectoryInfo(saveFileLocation);
var bookmarkFiles = replaceDir.GetFiles().ToList();
foreach (var bkmFile in bookmarkFiles)
{
if (SearchReplaceBookmarks(bkmFile.FullName))
{
Console.WriteLine("Bookmarks Replace:" + bkmFile.Name + " ::: ");
}
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR: ::: " + ex.Message);
}
}
static string startDir = Path.GetDirectoryName(Util.CurrentQueryPath);
string saveFileLocation = startDir + #"\Converted\";
private List<fieldReplace> fieldList = new List<fieldReplace>() {
//new fieldReplace("",""),
new fieldReplace("~{U-nm}","_Doctor"),
new fieldReplace("~{P-nl}","_Patient_Surname","Patient_Firstname"),
new fieldReplace("~{DOBN}","_Patient_DOB"),
new fieldReplace("~{U-ph","_Doctor_PhoneWork"),//Surgeon Business
new fieldReplace("~{U-pm}","_Doctor_PhoneMobile")//Surgeon After Hours
}
// Define other methods and classes here
private bool SearchReplaceBookmarks(string filename)
{
try
{
WordDocument wordDocument = new WordDocument(filename);
//Adds one section and one paragraph to the document
foreach (var fld in fieldList)
{
var replaceBookmark = wordDocument.Find(fld.TextToReplace, false, true);
//if the bookmark is in the list then
while (replaceBookmark != null)
{
//Find and replace text with merge field.
var paragraph = new WParagraph(wordDocument);
for (int i =0 ; i<= fld.FieldNames.Length-1;i++){
var field = paragraph.AppendField(fld.FieldNames[i], FieldType.FieldMergeField);
field.FieldType = FieldType.FieldMergeField;
if (i < fld.FieldNames.Length - 1) { paragraph.AppendText(", ");}
}
var selection = new TextSelection(paragraph, 0, paragraph.Text.Length);
wordDocument.Replace(fld.TextToReplace, selection, true, true); //This is where the Merge Field is meant to be inserted
replaceBookmark = wordDocument.FindNext(paragraph, fld.TextToReplace, false, true);
}
}
//Debug.Write( wordDocument.MailMerge.MappedFields);
wordDocument.Save(filename, FormatType.Docx);
wordDocument.Close();
return true;
}
catch (Exception ex)
{
Console.WriteLine("ERROR:" + filename + " ::: " + ex.Message);
return false;
}
}
private class fieldReplace
{
public fieldReplace(string oldText, params string[] newNewFieldName)
{
this.TextToReplace = oldText;
this.FieldNames = newNewFieldName;
}
public string TextToReplace { get; set; }
public string[] FieldNames { get; set; }
}

On analyzing on your mentioned scenario,
1) Finding the place holder text from the Word document.
2) Replacing the place holder text with the merge fields and the fields to be replaced as such in MS Word document.
Yes, using DocIO the place holder text can be replaced with merge fields as equivalent to MS Word. We have modified your code to achieve your requirement. We have used TextBodyPart overload of the Replace() method. Please find the below code snippet.
Modified Code Snippet
TextBodyPart bodyPart = new TextBodyPart(wordDocument);
bodyPart.BodyItems.Add(paragraph); wordDocument.Replace(fld.TextToReplace, bodyPart, true, true);
For further questions please contact our support team at support#syncfusion.com to get a prompt assistance on this.

Related

Cleaning up nested if statements to be more readable?

I'm writing a project, and the part I'm doing now is getting arrow shaped real fast. How can I remove the nested if statements, but still have the same behaviour?
The code below might not look so bad now, but I'm planning on refactoring to include more methods.
public async Task FirstDiffTestAsync()
{
string folderDir = "../../../";
string correctReportDir = folderDir + "Reports To Compare/Testing - Copy.pdf";
string OptyNumber = "122906";
//Making a POST call to generate report
string result = ReportGeneration(OptyNumber).Result;
Response reportResponse = JsonConvert.DeserializeObject<Response>(result);
string newURL = reportResponse.documentUrl;
//Logging the Response to a text file for tracking purposes
await File.WriteAllTextAsync(Context.TestRunDirectory + "/REST_Response.txt", result);
using (StreamWriter w = File.AppendText(Context.TestDir + "/../log.txt"))
{
//Checking if the Integration failed
if (reportResponse.Error == null)
{
//now we have the url, reading in the pdf reports
List<string> Files = new List<string> { correctReportDir, newURL };
List<string> parsedText = PdfToParsedText(Files);
DiffPaneModel diff = InlineDiffBuilder.Diff(parsedText[0], parsedText[1]);
// DiffReport is a customised object
DiffReport diffReport = new DiffReport(correctReportDir, newURL);
diffReport.RunDiffReport(diff);
//In-test Logging
string indent = "\n - ";
string logMsg = $"{indent}Opty Number: {OptyNumber}{indent}Activity Number: {reportResponse.ActivityNumber}{indent}File Name: {reportResponse.FileName}";
if (diffReport.totalDiff != 0)
{
await File.WriteAllTextAsync(Context.TestRunDirectory + "/DiffReport.html", diffReport.htmlDiffHeader + diffReport.htmlDiffBody);
logMsg += $"{indent}Different lines: {diffReport.insertCounter} Inserted, {diffReport.deleteCounter} Deleted";
}
LogTesting(logMsg, w);
//Writing HTML report conditionally
if (diffReport.totalDiff != 0)
{
await File.WriteAllTextAsync(Context.TestRunDirectory + "/DiffReport.html", diffReport.htmlDiffHeader + diffReport.htmlDiffBody);
}
Assert.IsTrue(diffReport.insertCounter + diffReport.deleteCounter == 0);
}
else
{
LogTesting($" Integration Failed: {reportResponse.Error}", w);
Assert.IsNull(reportResponse.Error);
}
}
}
As mentioned in the comment, the indentation level is fine for now, but its always better to minimize when possible, especially when you are repeating same blocks of code.
The best way to do this is to write a separate function that contains that block of code and then call that function instead of the nested if statements.
In your case it would be something like this:
private async void checkTotalDiff(diffReport) {
...
}
You could pass anything you might need in the parameters. This way in your main code, you could replace the if statements with checkTotalDiff(diffReport) and save the return (if any) to a variable.
Also note I used void for return but you could change the type depending on what the function returns.
I wouldn't consider this as having an excessive amount of nested if-statements. It is fine as is. Otherwise you could do the following (also suggested by #Caius Jard):
public async Task FirstDiffTestAsync()
{
string folderDir = "../../../";
string correctReportDir = folderDir + "Reports To Compare/Testing - Copy.pdf";
string OptyNumber = "122906";
//Making a POST call to generate report
string result = ReportGeneration(OptyNumber).Result;
Response reportResponse = JsonConvert.DeserializeObject<Response>(result);
//Checking if the Integration failed
if (reportResponse.Error != null)
{
LogTesting($" Integration Failed: {reportResponse.Error}", w);
Assert.IsNull(reportResponse.Error);
return;
}
string newURL = reportResponse.documentUrl;
//Logging the Response to a text file for tracking purposes
await File.WriteAllTextAsync(Context.TestRunDirectory + "/REST_Response.txt", result);
using (StreamWriter w = File.AppendText(Context.TestDir + "/../log.txt"))
{
//now we have the url, reading in the pdf reports
List<string> Files = new List<string> { correctReportDir, newURL };
List<string> parsedText = PdfToParsedText(Files);
DiffPaneModel diff = InlineDiffBuilder.Diff(parsedText[0], parsedText[1]);
// DiffReport is a customised object
DiffReport diffReport = new DiffReport(correctReportDir, newURL);
diffReport.RunDiffReport(diff);
//In-test Logging
string indent = "\n - ";
string logMsg = $"{indent}Opty Number: {OptyNumber}{indent}Activity Number: {reportResponse.ActivityNumber}{indent}File Name: {reportResponse.FileName}";
if (diffReport.totalDiff != 0)
{
await File.WriteAllTextAsync(Context.TestRunDirectory + "/DiffReport.html", diffReport.htmlDiffHeader + diffReport.htmlDiffBody);
logMsg += $"{indent}Different lines: {diffReport.insertCounter} Inserted, {diffReport.deleteCounter} Deleted";
}
LogTesting(logMsg, w);
//Writing HTML report conditionally
if (diffReport.totalDiff != 0)
{
await File.WriteAllTextAsync(Context.TestRunDirectory + "/DiffReport.html", diffReport.htmlDiffHeader + diffReport.htmlDiffBody);
}
Assert.IsTrue(diffReport.insertCounter + diffReport.deleteCounter == 0);
}
}

Cannot Write Multiple Paragraph in Aspose

I have an issue when I try to write multiple paragraphs in existing Shape. Only the first paragraph is written. I debug the code and I found that the Shape object as all the paragraphs I want. The problem is when I write to file I found only the first one. I share with you the project code.
class Program
{
public static void Run()
{
string dataDir = ConfigurationManager.AppSettings["directoryToSave"];
string srcDir = ConfigurationManager.AppSettings["Source"];
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string file = Path.Combine(appData, srcDir);
using (Presentation presentation = new Presentation(srcDir))
{
IMasterLayoutSlideCollection layoutSlides = presentation.Masters[0].LayoutSlides;
ILayoutSlide layoutSlide = null;
foreach (ILayoutSlide titleAndObjectLayoutSlide in layoutSlides)
{
if (titleAndObjectLayoutSlide.Name == "TITRE_CONTENU")
{
layoutSlide = titleAndObjectLayoutSlide;
break;
}
}
var contenu = File.ReadAllText(#"E:\DemosProject\PF_GEN\PF_GEN\Source\contenu.txt", Encoding.UTF8);
IAutoShape contenuShape = (IAutoShape)layoutSlide.Shapes.SingleOrDefault(r => r.Name.Equals("contenu"));
ITextFrame txt = ((IAutoShape)contenuShape).TextFrame;
txt.Paragraphs.Clear();
string[] lines = contenu.Split(new[] { Environment.NewLine }, StringSplitOptions.None).Where(str => !String.IsNullOrEmpty(str)).ToArray();
for (int i = 0; i < lines.Length; i++)
{
var portion = new Portion();
portion.Text = lines[i];
var paragraphe = new Paragraph();
paragraphe.Portions.Add(portion);
txt.Paragraphs.Add(paragraphe);
}
presentation.Slides.InsertEmptySlide(0, layoutSlide);
presentation.Save(dataDir + "AddLayoutSlides_out.pptx", SaveFormat.Pptx);
}
}
static void Main(string[] args)
{
try
{
var path = ConfigurationManager.AppSettings["sourceAsposeLicensePath"];
License license = new License();
license.SetLicense(path);
Run();
}
catch (Exception ex)
{
Console.WriteLine("Error" + ex.Message);
}
finally
{
Console.WriteLine("Terminated");
Console.ReadKey();
}
}
}
You can find the ppt file (source file) in the attachement file. (https://gofile.io/?c=JpBDS8 1)
Is there any thing missing in my code?
Thanks
I have observed your requirements and suggest you to please try using following sample code on your end. In your sample code, you are adding different paragraphs to a shape inside LayoutSlide and then adding a slide using that LayoutSlide to contain the desired shape. This approach is not correct. You actually need to first add slide based on LayoutSlide and then add text to that shape as per your requirements. The following code will be helpful to you.
public static void RunParaText()
{
string path = #"C:\Aspose Data\";
string dataDir = path;
string srcDir = path + "Master.pptx";
//string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
//string file = Path.Combine(appData, srcDir);
using (Presentation presentation = new Presentation(srcDir))
{
IMasterLayoutSlideCollection layoutSlides = presentation.Masters[0].LayoutSlides;
ILayoutSlide layoutSlide = null;
foreach (ILayoutSlide titleAndObjectLayoutSlide in layoutSlides)
{
if (titleAndObjectLayoutSlide.Name == "TITRE_CONTENU")
{
layoutSlide = titleAndObjectLayoutSlide;
break;
}
}
var contenu = File.ReadAllText(dataDir+"contenu.txt", Encoding.UTF8);
var slide=presentation.Slides.InsertEmptySlide(0, layoutSlide);
IAutoShape contenuShape = (IAutoShape)slide.Shapes.SingleOrDefault(r => r.Name.Equals("contenu"));
//IAutoShape contenuShape = (IAutoShape)layoutSlide.Shapes.SingleOrDefault(r => r.Name.Equals("contenu"));
ITextFrame txt = ((IAutoShape)contenuShape).TextFrame;
txt.Paragraphs.Clear();
string[] lines = contenu.Split(new[] { Environment.NewLine }, StringSplitOptions.None).Where(str => !String.IsNullOrEmpty(str)).ToArray();
for (int i = 0; i < lines.Length; i++)
{
var portion = new Portion();
portion.Text = lines[i];
var paragraphe = new Paragraph();
paragraphe.Portions.Add(portion);
txt.Paragraphs.Add(paragraphe);
}
//Change font size w.r.t shape size
contenuShape.TextFrame.TextFrameFormat.AutofitType = TextAutofitType.Normal;
presentation.Save(dataDir + "AddLayoutSlides_out.pptx", SaveFormat.Pptx);
}
}
I am working as Support developer/ Evangelist at Aspose.

How to get text of perticular area in scanned file from many file to save with that text to file

I am making small for scanned file reader in c#.
client requirment is to provide facility to select area in scan file by which he can specify which have to read.
I made this using below code
public string ReadCharacter(string fileName)
{
string value = "";
try
{
Image<Emgu.CV.Structure.Gray, byte> img = new Image<Emgu.CV.Structure.Gray, byte>(fileName);
System.Drawing.Rectangle staticRec = new System.Drawing.Rectangle(General.Rect_X, General.Rect_Y, General.Rect_Width, General.Rect_Height);
//img.ROI = staticRec;
var _ocr = new Tesseract(#"D:\", "eng", OcrEngineMode.TesseractCubeCombined);
_ocr.SetVariable("tessedit_char_whitelist", "1234567890");
_ocr.Recognize(img);
General.selectedString = _ocr.GetText();
char[] array1 = { '\n', '\r' };
General.selectedString = General.selectedString.Trim(array1);
img.ROI = staticRec;
_ocr.Recognize(img);
value = _ocr.GetText();
// MessageBox.Show(value);
}
catch (Exception ex)
{
MessageBox.Show("Please Select Valid Area " + ex.Message);
}
// MessageBox.Show(value);
return value;
}
but it not working properly with all files.
Any one can help me please.

How to validate the text inside Uploaded file in asp.net

How to validate the text inside a .csv? I want to check the data and don’t save it, if at least 1 line of the file is incorrect.
Example data:
ISPROG3,09-23-14,BATMAN #correct
ISPROG2,08-23-14,SUPERMAN #correct
KRISTERKRISTEKRISTER #wrong
My code:
try
{ //this determines the type of extension that is only allowed in the fileupload
string ext = System.IO.Path.GetExtension(FileUpload1.PostedFile.FileName);
string[] allowedExtenstions = new string[] { ".txt", ".csv"};
if (allowedExtenstions.Contains(ext))
{ //if the extension is qualified then we proceed with the upload
string uploadfile = Server.MapPath("~/Upload/");//create first a folder where we will store the uploaded file
uploadfile += FileUpload1.FileName;
if (File.Exists(uploadfile))
{
File.Delete(uploadfile);
}
FileUpload1.PostedFile.SaveAs(uploadfile);
if (File.Exists(uploadfile))
{
using (StreamReader sr = File.OpenText(uploadfile))// we read the file line by line
{
string inputline = "";
while ((inputline = sr.ReadLine()) != null)
{
string temp = inputline;
string name = temp.Substring(0, temp.IndexOf(","));//Name is from the first index [0] until the index of the first comma
temp = temp.Substring(temp.IndexOf(",") + 1);// Only retain the date and feedbacks fields
string date = temp.Substring(0, temp.IndexOf(","));//date is the start of the first index[0] until the index of the first comma
temp = temp.Substring(temp.IndexOf(",") + 1);//we cut the date and retain feedbacks
string feedbacks = temp;
upload.ID = int.Parse(txtID.Text);//it's in the textbox read-only
upload.Name = name;//upload.name comes from my business logic layer
upload.Date = date;//upload.date comes from my business logic layer
upload.Feedbacks = feedbacks;
upload.adduploads();//add function to transfer to the database
GridView2.DataSource = upload.search();//we view the added value
GridView2.DataBind();
}
}
}
}
else
{
Label39.Text = "NOTEPAD AND CSV FILE ONLY";
}
}
catch (Exception ex)
{
Label39.Text = "*" + ex.Message;
}
You could count the comma in your line, if that's the only problem and use it in an if check:
string temp = inputline;
bool saveFile = true;
// check for amount of comma in line
if(temp.Split(',').Length - 1 != 2) {
saveFile = false;
}
if(saveFile) {
// your save code
}

Gedcom Reader for C#

Does anyone know of a good class to read in .ged files
Gedcom is a file format that is used to store genealogical information.
My goal is to write something that would let me import a ged file and export a .dot file for graphviz so that I can make a visual representation of a family tree
thanks if you can help
Heres my best attempt so far.
It seems to be working for what i need though its defiently not full proof ( then again my family tree is rather large and that adds some complexity)
please let me know if you think i could make anything more elequient
struct INDI
{
public string ID;
public string Name;
public string Sex;
public string BirthDay;
public bool Dead;
}
struct FAM
{
public string FamID;
public string type;
public string IndiID;
}
List<INDI> Individuals = new List<INDI>();
List<FAM> Family = new List<FAM>();
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\mostrecent.ged";
ParseGedcom(path);
}
private void ParseGedcom(string path)
{
//Open path to GED file
StreamReader SR = new StreamReader(path);
//Read entire block and then plit on 0 # for individuals and familys (no other info is needed for this instance)
string[] Holder = SR.ReadToEnd().Replace("0 #", "\u0646").Split('\u0646');
//For each new cell in the holder array look for Individuals and familys
foreach (string Node in Holder)
{
//Sub Split the string on the returns to get a true block of info
string[] SubNode = Node.Replace("\r\n", "\r").Split('\r');
//If a individual is found
if (SubNode[0].Contains("INDI"))
{
//Create new Structure
INDI I = new INDI();
//Add the ID number and remove extra formating
I.ID = SubNode[0].Replace("#", "").Replace(" INDI", "").Trim();
//Find the name remove extra formating for last name
I.Name = SubNode[FindIndexinArray(SubNode, "NAME")].Replace("1 NAME", "").Replace("/", "").Trim();
//Find Sex and remove extra formating
I.Sex = SubNode[FindIndexinArray(SubNode, "SEX")].Replace("1 SEX ", "").Trim();
//Deterine if there is a brithday -1 means no
if (FindIndexinArray(SubNode, "1 BIRT ") != -1)
{
// add birthday to Struct
I.BirthDay = SubNode[FindIndexinArray(SubNode, "1 BIRT ") + 1].Replace("2 DATE ", "").Trim();
}
// deterimin if there is a death tag will return -1 if not found
if (FindIndexinArray(SubNode, "1 DEAT ") != -1)
{
//convert Y or N to true or false ( defaults to False so no need to change unless Y is found.
if (SubNode[FindIndexinArray(SubNode, "1 DEAT ")].Replace("1 DEAT ", "").Trim() == "Y")
{
//set death
I.Dead = true;
}
}
//add the Struct to the list for later use
Individuals.Add(I);
}
// Start Family section
else if (SubNode[0].Contains("FAM"))
{
//grab Fam id from node early on to keep from doing it over and over
string FamID = SubNode[0].Replace("# FAM", "");
// Multiple children can exist for each family so this section had to be a bit more dynaimic
// Look at each line of node
foreach (string Line in SubNode)
{
// If node is HUSB
if (Line.Contains("1 HUSB "))
{
FAM F = new FAM();
F.FamID = FamID;
F.type = "PAR";
F.IndiID = Line.Replace("1 HUSB ", "").Replace("#","").Trim();
Family.Add(F);
}
//If node for Wife
else if (Line.Contains("1 WIFE "))
{
FAM F = new FAM();
F.FamID = FamID;
F.type = "PAR";
F.IndiID = Line.Replace("1 WIFE ", "").Replace("#", "").Trim();
Family.Add(F);
}
//if node for multi children
else if (Line.Contains("1 CHIL "))
{
FAM F = new FAM();
F.FamID = FamID;
F.type = "CHIL";
F.IndiID = Line.Replace("1 CHIL ", "").Replace("#", "");
Family.Add(F);
}
}
}
}
}
private int FindIndexinArray(string[] Arr, string search)
{
int Val = -1;
for (int i = 0; i < Arr.Length; i++)
{
if (Arr[i].Contains(search))
{
Val = i;
}
}
return Val;
}
There is a very pretty one at Codeplex: FamilyShow (a WPF showcase). It imports/exports GEDCOM 5.5 and there is source.
I would actually have been surprised if there wasn't at least the beginnings of one. I found Gedcom.NET (sourceforge) quite easily
I'd be fairly surprised if there was a C# reader for this format available on the web, given that it's a fairly specialized format. On the upside, the format looks to be pretty straightforward to read if you need to create your own reader. I would suggest going down that path and coming back to SO if you have specific questions about the implementation. Take a look at the System.IO.StreamReader class; it's trivial to read in a file line-by-line that way, and parsing the individual lines should be simple as well.
Good luck!
I found a fresh project GedcomParser.

Categories

Resources