Dmitry
Dmitry

Reputation: 2158

c# openxml : copy paragraph with font and alignment

I want to copy a part of word *.docx to another *.docx file. For this I get a list of paragraphs from the original file :

private static List<Paragraph> getTextItems( string origFile )
{
    List<Paragraph> paragraphItems = new List<Paragraph>();
    var parser = new LineTextParser();

    using (var doc = WordprocessingDocument.Open( origFile, false))
    {

        foreach (var el in doc.MainDocumentPart.Document.Body.Elements().OfType<Paragraph>())
        {
            if (parser.isHorizontalTableLine(el.InnerText))
            {
                if (true == el.InnerText.EndsWith("|"))
                {
                    break;
                }
            }
            paragraphItems.Add(el);
        }
    }

    return paragraphItems;
}

Then I'm trying to apply these items to a new file :

    using (WordprocessingDocument wordDocument =
        WordprocessingDocument.Create(resultFile, WordprocessingDocumentType.Document))
    {
        // Add a main document part. 
        MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();

        // Create the document structure and add some text.
        mainPart.Document = new Document();
        Body body = mainPart.Document.AppendChild(new Body());
        foreach (var item in paragraphItems)
        {
            Paragraph para = body.AppendChild(new Paragraph() );
            para.Append(item.ParagraphProperties.CloneNode(true));
            Run run = para.AppendChild(new Run());
            run.AppendChild(new Text(item.InnerText));
        }
    }

But original formatting is lost - I mean the font has been changed and also alignment. What is the solution here?

Upvotes: 0

Views: 3305

Answers (1)

haldo
haldo

Reputation: 16701

First, instead of item.InnerText use item.InnerXml and set the new paragraph Xml to the source paragraph Xml.

You just need to re-order the way the paragraphs are being appended to the document. The method below should create the file with the paragraphs copied from the original document.

public void CreateFile(string resultFile, List<Paragraph> paragraphItems)
{
    using (WordprocessingDocument wordDocument =
           WordprocessingDocument.Create(resultFile, WordprocessingDocumentType.Document))
    {
        MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();

        mainPart.Document = new Document();
        Body body = mainPart.Document.AppendChild(new Body());

        foreach (var item in paragraphItems)
        {
            Paragraph para = new Paragraph();

            // set the inner Xml of the new paragraph
            para.InnerXml = item.InnerXml;

            // append paragraph to body here
            body.AppendChild(para);
        }
    }
}

Now we need to apply the styles from doc.MainDocumentPart.StyleDefinitionsPart to the new document.

This following method was modified from this MSDN guide. It extracts the styles from StyleDefinitionsPart as an XDocument.

public XDocument ExtractStylesPart(string sourceFile)
{
    XDocument styles = null;

    // open readonly
    using (var document = WordprocessingDocument.Open(sourceFile, false))
    {
        var docPart = document.MainDocumentPart;

        StylesPart stylesPart = docPart.StyleDefinitionsPart;

        if (stylesPart != null)
        {
            using (var reader = XmlNodeReader.Create(
                       stylesPart.GetStream(FileMode.Open, FileAccess.Read)))
            {
                // Create the XDocument.
                styles = XDocument.Load(reader);
            }
        }
    }
    // Return the XDocument instance.
    return styles;
} 

Then you need to save the style to the new document. The following method should work for you:

public void SetStyleToTarget(string targetFile, XDocument newStyles)
{
    // open with write permissions
    using (var doc = WordprocessingDocument.Open(targetFile, true))
    {
            // add or get the style definition part
            StyleDefinitionsPart styleDefn = null;
            if (doc.MainDocumentPart.StyleDefinitionsPart == null)
            {
                styleDefn = doc.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();
            }
            else
            {
                styleDefn = doc.MainDocumentPart.StyleDefinitionsPart;
            }

        // populate part with the new styles
        if (styleDefn != null)
        {
            // write the newStyle xDoc to the StyleDefinitionsPart using a streamwriter
            newStyles.Save(new StreamWriter(
                           styleDefn.GetStream(FileMode.Create, FileAccess.Write)));
        }
        // probably not needed (works for me with or without this save)
        doc.Save();
    }
}

The above method was inspired by the guide linked earlier. The difference is that this creates a new style element for the new document (because it doesn't have one - we just created the doc).

I only used StyleDefinitionsPart but there is another part StylesWithEffectsPart. You may need to implement similar method for the StylesWithEffectsPart if your document uses it.

Upvotes: 1

Related Questions