Apply style on custom tag

Hi,

Our client want to be able to insert subtitles in his text. I give you 2 attachments to illustrate my need:

  • No manipulation.png: What I have without manipulation(text is extracted from SQL DB)

  • Result.png: What our client wants

The text is HTML.

I have to change the font (size, color, italic) and also the paragraph (SpaceBefore = 6, SpaceAfter = 3).

Thank you have a nice day!!

Steeve

Hi Steeve,

Thanks for your inquiry. Please read the following article that outlines the basics of ‘Find and Replace’ functionality of Aspose.Words:
https://docs.aspose.com/words/java/find-and-replace/
https://docs.aspose.com/words/java/find-and-replace/

In your case, I suggest you please implement the IReplacingCallback interface as shown in following code snippet. Hope this helps you.

private class MyReplaceEvaluator_10: IReplacingCallback
{
    ///
    /// This is called during a replace operation each time a match is found.
    /// This method appends a number to the match string and returns it as a replacement string.
    ///
    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 highlighting.
        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);
        }
        DocumentBuilder builder = new DocumentBuilder((Document) e.MatchNode.Document);
        builder.MoveTo((Run) runs[runs.Count - 1]);
        builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Subtitle;
        builder.Writeln("Some Text");
        foreach(Run run in runs)
        {
            run.Remove();
        }
        // Signal to the replace engine to do nothing because we have already done all what we wanted.
        return ReplaceAction.Skip;
    }
}

Hi Tahir,

It seems to work fine! I only changed the part highlighted to respect the client’s requirements :

Document doc = (Document) e.MatchNode.Document;
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveTo((Run) runs[runs.Count - 1]);

builder.Font.Name = "Arial";
builder.Font.Bold = false;
builder.Font.Italic = true;
builder.Font.Size = 11;
builder.Font.Color = ColorsAvailable[MyColor];

builder.ParagraphFormat.SpaceAfter = 3.0;
builder.ParagraphFormat.SpaceBefore = 6.0;

Thank you and have a nice day!!

Steeve

Hi Steeve,

Thanks for your feedback. Please feel free to ask if you have any question about Aspose.Words, we will be happy to help you.

Hi,

Finally, my idea was not good because I need to use Style. The final document is stored on disk (server-side) and the user can use a existing document and change the color of the subitle via the application. So, I tried this, but it does not work (see attachment and code below). My custom style is always duplicated (Name + 9pt, black).

// Creation of the style
public static void CreateSubTitleStyle(ref Document doc, Color subTitleColor)
{
    Style stylesubTitle = doc.Styles.Add(StyleType.Character, "PFS_DATA_SUBTITLE");
    stylesubTitle.Font.Name = "Arial";
    stylesubTitle.Font.Bold = false;
    stylesubTitle.Font.Italic = true;
    stylesubTitle.Font.Size = 11;
    stylesubTitle.Font.Color = subTitleColor;
}

// This is my call for the replace
foreach(Subtitle subTitle in subTitles)
{
    Regex regexSub = new Regex(subTitle.Tag, RegexOptions.IgnoreCase);
    doc.Range.Replace(regexSub, new ReplacingCallbackSustitle(subTitle), true);
}

ReplacingCallbackSustitle--> See Attachment
Result.docx--> See Attachment

If I use only the builder, I can’t find my subtitle in the existing document.

I hope you can help me…

Thank you and have a nice day

Steeve

Hi Steeve,

Thanks for your inquiry. You can set the following font properties by using DocumentBuilder.Font.xxxx in IReplacingCallback.Replacing.

stylesubTitle.Font.Name = "Arial";
stylesubTitle.Font.Bold = false;
stylesubTitle.Font.Italic = true;
stylesubTitle.Font.Size = 11;
stylesubTitle.Font.Color = subTitleColor;

cardis1:
My custom style is always duplicated (Name + 9pt, black).

Are you facing this issue while using the shared code (ReplacingCallbackSustitle)? If yes, please attach your input Word document here for testing? I will investigate the issue on my side and provide you more information.

Hi,

I suppose that is not the best solution, but it works…

This is my constructor:

public ReplacingCallbackSustitle(Subtitle subtitle, bool formatOnly)
{
    // SubTitleToReplace = new Subtitle { SubtitleNm = subtitle.SubtitleNm};
    SubTitleToReplace = subtitle;
    FormatOnly = formatOnly;
}

I call 2 times the replace

  • For the format paragraph and font
  • “Real” Replace

This is inside the IReplacingCallback.Replacing

Document doc = (Document) e.MatchNode.Document;
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveTo((Run) runs[runs.Count - 1]);

builder.ParagraphFormat.SpaceAfter = 3.0;
builder.ParagraphFormat.SpaceBefore = 6.0;

Font font = builder.Font;

if (FormatOnly)
{
    Style styleSubTitle = doc.Styles["PFS_DATA_SUBTITLE"];
    font.Italic = styleSubTitle.Font.Italic;
    font.Size = styleSubTitle.Font.Size;
    font.Bold = styleSubTitle.Font.Bold;
    font.Color = styleSubTitle.Font.Color;
    builder.Write(SubTitleToReplace.Tag); // rewrite the same tag (undo the replace)
}
else
{
    font.Style = doc.Styles["PFS_DATA_SUBTITLE"];
    font.Italic = font.Style.Font.Italic;
    font.Size = font.Style.Font.Size;
    font.Bold = font.Style.Font.Bold;
    font.Color = font.Style.Font.Color;
    builder.Write(SubTitleToReplace.SubtitleNm); // Replace the tag by its text
}

Thank you for your time and have a nice day

Steeve

Hi Steeve,

Thanks for your inquiry.

Please note that formatting is applied on a few different levels. For example, let’s consider formatting of simple text. Text in documents is represented by Run element and a Run can only be a child of a Paragraph. You can apply formatting 1) to Run nodes by using Character Styles e.g. a Glyph Style, 2) to the parent of those Run nodes i.e. a Paragraph node (possibly via paragraph Styles) and 3) you can also apply direct formatting to Run nodes by using Run attributes (Font). In this case the Run will inherit formatting of Paragraph Style, a Glyph Style and then direct formatting.

In your case, you can apply direct formatting as you are currently doing. You may create and use a paragraph style as shown in following code snippet.

Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
// Create a paragraph style and specify some formatting for it.
Style style = doc.Styles.Add(StyleType.Paragraph, "MyStyle1");
style.Font.Size = 24;
style.Font.Name = "Verdana";
style.ParagraphFormat.SpaceAfter = 12;
// Apply the paragraph style to the current paragraph in the document and add some text.
builder.ParagraphFormat.Style = style;
builder.Writeln("Hello World");
// Change to a paragraph style that has no list formatting.
builder.ParagraphFormat.Style = doc.Styles["Normal"];
builder.Writeln("Hello World: Normal.");