Table in If Field

Hi,

How can I create If Field with a Table node as one of its results?

Thanks,
Łukasz

@acturisaspose,

Please check following template and output Word documents where I placed a Table inside True part of IF field. The following C# code will show the Table while specifying false to merge field will hide it.

Document doc = new Document("C:\\temp\\Table inside true part of IF field\\Table inside true part of IF field.docx");
doc.MailMerge.Execute(new string[] { "show" }, new object[] { "true" });
doc.Save("C:\\Temp\\Table inside true part of IF field\\21.3.docx");

Hi, thank you.

Is there any way I can do it purely programmatically?
I mean construct such IF with table from scratch in code without using template.

Thanks,
Łukasz

@acturisaspose,

You can build logic on the following code to programmatically insert such IF field with merge field and Table:

Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);

// { IF "{ MERGEFIELD show }" = "<<Table>>" "False Part" }

Field field = builder.InsertField("IF \"", null);

builder.MoveTo(field.Start.NextSibling.NextSibling);

// Insert merge field and expression
FieldMergeField mergeField = (FieldMergeField)builder.InsertField(FieldType.FieldMergeField, false);
mergeField.FieldName = "show";

builder.Write("\" = \"true\" \"");

// Write True part of IF Field
// In our case, its a Table
builder.StartTable();

builder.InsertCell();
builder.CellFormat.VerticalAlignment = CellVerticalAlignment.Center;
builder.Write("This is row 1 cell 1");

builder.InsertCell();
builder.Write("This is row 1 cell 2");

builder.EndRow();

builder.InsertCell();
builder.Writeln("This is row 2 cell 1");

builder.InsertCell();
builder.Writeln("This is row 2 cell 2");

builder.EndRow();
builder.EndTable();

// Write False part of IF Field
builder.Write("\" \"Don't show\"");

// perform Mail Merge
doc.MailMerge.Execute(new string[] { "show" }, new object[] { "true" });

doc.Save("C:\\Temp\\21.3.docx");

Hi,

thank you for the example.
Could you please let me know if this is possible when I have already existing document with If field and I want to replace true result, which is a bookmark, with a table?
How can I easily insert a table in its true result?

thanks,
Łukasz

@acturisaspose,

You can first place a keyword or marker inside the true part of the target IF field and then using Find and Replace functionality of Aspose.Words, replace that keyword marker with Table or other content:

Document doc = new Document("C:\\temp\\Table inside true part of IF field.docx");

foreach (Field field in doc.Range.Fields)
{
    if (field.Type == FieldType.FieldIf)
    {
        FieldIf ifField = (FieldIf)field;
        ifField.TrueText = "TrueText"; // use a keyword/marker here
        ifField.Update();
        break;
    }
}

FindReplaceOptions options = new FindReplaceOptions();
// options.ReplacingCallback = ...
doc.Range.Replace("TrueText", "", options); // find that keyword and replace with Table etc

doc.Save("C:\\Temp\\21.3.docx");

Hi,

thanks. I can see that Replace method takes string as a second parameter.
How can I use it to place a table object there?

Thanks,
Łukasz

@acturisaspose,

You can implement IReplacingCallback interface if you want to insert custom content during a find and replace operation:

Document doc = new Document("C:\\temp\\Table inside true part of IF field.docx");

foreach (Field field in doc.Range.Fields)
{
    if (field.Type == FieldType.FieldIf)
    {
        FieldIf ifField = (FieldIf)field;
        ifField.TrueText = "TrueText"; // use a keyword/marker here
        ifField.Update();
        break;
    }
}

FindReplaceOptions options = new FindReplaceOptions();
options.ReplacingCallback = new ReplaceEvaluator();
doc.Range.Replace("TrueText", "", options); // find that keyword and replace with Table etc

doc.MailMerge.Execute(new string[] { "show" }, new object[] { "true" });

doc.Save("C:\\Temp\\21.3.docx");

private class ReplaceEvaluator : IReplacingCallback
{
    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
    {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.MatchNode;

        // The first (and may be the only) run can contain text before the match,
        // in this case it is necessary to split the run.
        if (e.MatchOffset > 0)
            currentNode = SplitRun((Run)currentNode, e.MatchOffset);

        // This array is used to store all nodes of the match for further removing.
        ArrayList runs = new ArrayList();

        // Find all runs that contain parts of the match string.
        int remainingLength = e.Match.Value.Length;
        while (
            (remainingLength > 0) &&
            (currentNode != null) &&
            (currentNode.GetText().Length <= remainingLength))
        {
            runs.Add(currentNode);
            remainingLength = remainingLength - currentNode.GetText().Length;

            // Select the next Run node.
            // Have to loop because there could be other nodes such as BookmarkStart etc.
            do
            {
                currentNode = currentNode.NextSibling;
            }
            while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
        }

        // Split the last run that contains the match if there is any text left.
        if ((currentNode != null) && (remainingLength > 0))
        {
            SplitRun((Run)currentNode, remainingLength);
            runs.Add(currentNode);
        }

        //// to insert Table
        DocumentBuilder builder = new
        DocumentBuilder((Document)e.MatchNode.Document);

        builder.MoveTo((Run)runs[runs.Count - 1]);

        Table table = builder.StartTable();

        builder.InsertCell();
        builder.Write("This is row 1 cell 1");
        builder.InsertCell();
        builder.Write("This is row 1 cell 2");
        builder.EndRow();                

        builder.EndTable();

        foreach (Run run in runs)
            run.Remove();

        return ReplaceAction.Skip;
    }

    public static Run SplitRun(Run run, int position)
    {
        Run afterRun = (Run)run.Clone(true);
        afterRun.Text = run.Text.Substring(position);
        run.Text = run.Text.Substring((0), (0) + (position));
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }
}

Hi,

Thanks for all your help.

I am still struggling as I want to import an existing table to true result from another document.
I get an error that I cannot Insert node of this type at this lcoation :confused:

Do you have any advice?

Thanks,
Łukasz

@acturisaspose,

You first need to import a Table node from another document to the current document and then insert it at desired position inside IF field. Please check the following methods:

Hi,

thank you. This is what I have tried and I still get the error that I cannot Insert node of this type at this location. I have tried using either NodeImporter or DocumentBase to ImportNodes, but I still get the error.
Please see the documents attached that I am using.
I want to replace EXT_0STAT bookmark in Aspose.dotx with content from Aspose.docx.
Could you please advise how to do it?
Aspose.zip (36.0 KB)

Thanks,
Łukasz

@acturisaspose,

The following code should insert Table inside the false part of IF field:

Document docx = new Document("C:\\Temp\\Aspose\\Aspose.docx");
Table table = docx.FirstSection.Body.Tables[0];

Document doc = new Document("C:\\Temp\\Aspose\\Aspose.dotx");
Table importedTable = (Table)doc.ImportNode(table, true);

foreach (Field field in doc.Range.Fields)
{
    if (field.Type == FieldType.FieldIf)
    {
        FieldIf ifField = (FieldIf)field;
        ifField.FalseText = "FalseText"; // use a keyword/marker here
        ifField.Update();
        break;
    }
}

FindReplaceOptions options = new FindReplaceOptions();
options.ReplacingCallback = new ReplaceEvaluator(importedTable);
doc.Range.Replace("FalseText", "", options); // find that keyword and replace with Table etc

//doc.MailMerge.Execute(new string[] { "show" }, new object[] { "true" });

doc.Save("C:\\Temp\\Aspose\\21.3.docx");

private class ReplaceEvaluator : IReplacingCallback
{
    Table _table = null;
    public ReplaceEvaluator(Table table)
    {
        _table = table;
    }

    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
    {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.MatchNode;

        // The first (and may be the only) run can contain text before the match,
        // in this case it is necessary to split the run.
        if (e.MatchOffset > 0)
            currentNode = SplitRun((Run)currentNode, e.MatchOffset);

        // This array is used to store all nodes of the match for further removing.
        ArrayList runs = new ArrayList();

        // Find all runs that contain parts of the match string.
        int remainingLength = e.Match.Value.Length;
        while (
            (remainingLength > 0) &&
            (currentNode != null) &&
            (currentNode.GetText().Length <= remainingLength))
        {
            runs.Add(currentNode);
            remainingLength = remainingLength - currentNode.GetText().Length;

            // Select the next Run node.
            // Have to loop because there could be other nodes such as BookmarkStart etc.
            do
            {
                currentNode = currentNode.NextSibling;
            }
            while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
        }

        // Split the last run that contains the match if there is any text left.
        if ((currentNode != null) && (remainingLength > 0))
        {
            SplitRun((Run)currentNode, remainingLength);
            runs.Add(currentNode);
        }

        //// to insert Table
        DocumentBuilder builder = new DocumentBuilder((Document)e.MatchNode.Document);

        builder.MoveTo((Run)runs[runs.Count - 1]);

        builder.Writeln();
        Paragraph para = (Paragraph)builder.CurrentParagraph.PreviousSibling;
        para.ParentNode.InsertAfter(_table, para);

        foreach (Run run in runs)
            run.Remove();

        return ReplaceAction.Skip;
    }

    public static Run SplitRun(Run run, int position)
    {
        Run afterRun = (Run)run.Clone(true);
        afterRun.Text = run.Text.Substring(position);
        run.Text = run.Text.Substring((0), (0) + (position));
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }
}