OpenXML Word - Adding Style to heading - c#

I am using this library to convert an html text to word format.
Everything works perfectly.
I need to style some of the text now. what I am using right now to generate document is that I have a list of heading and sub headings and heading text, I am using for each loop to get heading and subheading and its text and output them but I want these heading and subheading to assign heading1 to category and heading2 to sub category. here is what I got so far:
Foreach loop to get catagories and sub categories with its text
foreach (var category in ct)
{
strDocumentText.Append(category.ParentCat.CategoryName);
strDocumentText.Append("<br />");
if(category.DocumentText != null)
{
strDocumentText.Append(category.DocumentText);
}
if (category.Children != null)
{
foreach (var subCategoreis in category.Children)
{
strDocumentText.Append("<p />");
strDocumentText.Append(subCategoreis.ParentCat.CategoryName);
strDocumentText.Append("<br />");
if (category.DocumentText != null)
{
strDocumentText.Append(subCategoreis.DocumentText);
}
}
}
}
Create word document :
StringBuilder strDocumentText = new StringBuilder();
string html = strDocumentText.ToString();
using (MemoryStream generatedDocument = new MemoryStream())
{
BuildDocument(generatedDocument, html);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(generatedDocument, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = wordDoc.MainDocumentPart;
if (mainPart == null)
{
mainPart = wordDoc.AddMainDocumentPart();
new DocumentFormat.OpenXml.Wordprocessing.Document(new Body()).Save(mainPart);
}
HtmlConverter converter = new HtmlConverter(mainPart);
Body body = mainPart.Document.Body;
var paragraphs = converter.Parse(html);
for (int i = 0; i < paragraphs.Count; i++)
{
body.Append(paragraphs[i]);
}
mainPart.Document.Save();
}
fs.Close();
File.WriteAllBytes(saveFileDialog1.FileName, generatedDocument.ToArray());

First you need to add the style definitions to the document. The default styles are not included when constructing an OpenXml Document. After you define the styles, you can reference them in the paragraph properties element (serialized as "pPr") OR the run element properties. Take a look at: http://msdn.microsoft.com/en-us/library/cc850838.aspx

Related

Hebrew characters are printed in reverse order in iText 7

I'm using iText 7 for printing some text in List (in Hebrew) to PDF file, but while printing the Hebrew characters are printed in a reverse way.
The input given was "קניון אם הדרך" while the data printed in PDF is "ךרדה םא ןוינק"
I have set the font encoding and the base direction for the elements but still the characters are printed in the reverse order.
Code to print list into the table in PDF:
public void PrintListData(string filename)
{
var writer = new PdfWriter(filename);
PdfDocument pdfDoc = new PdfDocument(writer);
Document doc = new Document(pdfDoc, PageSize.A4);
SetFont(doc);
Table table = new Table(UnitValue.CreatePercentArray(2)).UseAllAvailableWidth();
table.SetTextAlignment(TextAlignment.RIGHT);
//table.SetBaseDirection(BaseDirection.RIGHT_TO_LEFT);
var index = 1;
foreach (var item in _data)
{
var para = new Paragraph(item);
para.SetTextAlignment(TextAlignment.RIGHT);
//para.SetBaseDirection(BaseDirection.RIGHT_TO_LEFT);
table.AddCell(index.ToString());
table.AddCell(para);
index++;
}
doc.Add(table);
doc.Close();
Process.Start(filename);
}
Set font function
void SetFont(Document doc)
{
FontSet _defaultFontSet = new FontSet();
var fontFolders = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
_defaultFontSet.AddFont(System.IO.Path.Combine(fontFolders, "arial.ttf"), PdfEncodings.IDENTITY_H);
_defaultFontSet.AddFont(System.IO.Path.Combine(fontFolders, "arialbd.ttf"), PdfEncodings.IDENTITY_H);
doc.SetFontProvider(new FontProvider(_defaultFontSet));
doc.SetProperty(Property.FONT, new String[] { "MyFontFamilyName" });
//doc.SetProperty(Property.BASE_DIRECTION, BaseDirection.RIGHT_TO_LEFT);
}
I'm not sure to where should we set the text direction to print RTL.

How to open docx file in ASP.NET MVC project using openxml for overwriting some text

I have searched a lot for the solution but can't find any.
I have a .docx file inside my MVC project folder which I want to open to overwrite some text but I'm unable to do so.
Inside my project folder, I have a Template folder and in this folder a genrated.docx file that I want to open. Here is my code:
using (WordprocessingDocument doc = WordprocessingDocument.Open
(#"~/Template/genrated.docx",true))
{
var body = doc.MainDocumentPart.Document.Body;
var paras = body.Elements<Paragraph>();
foreach (var para in paras)
{
foreach (var run in para.Elements<Run>())
{
foreach (var text in run.Elements<Text>())
{
if (text.Text.Contains("to-replace"))
{
text.Text = text.Text.Replace("to-replace", "replace-with");
run.AppendChild(new Break());
}
}
}
}
}
Please help me with this...
Your simplistic approach to replacing text only works in simple cases. Unfortunately, as soon as you use Microsoft Word to edit your template, your text "to-replace" might get split in multiple runs. This then means that you can't find your text "to-replace" if you only look for it in a single Text instance.
The following unit test demonstrates that by creating a document with two paragraphs, one having a single Text instance with your text "to-replace" and another one in which that same text is split into two Run and Text instances.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Xunit;
namespace CodeSnippets.Tests.OpenXml.Wordprocessing
{
public class SimplisticTextReplacementTests
{
private const string ToReplace = "to-replace";
private const string ReplaceWith = "replace-with";
private static MemoryStream CreateWordprocessingDocument()
{
var stream = new MemoryStream();
const WordprocessingDocumentType type = WordprocessingDocumentType.Document;
using WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, type);
MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
mainDocumentPart.Document =
new Document(
new Body(
new Paragraph(
new Run(
new Text(ToReplace))),
new Paragraph(
new Run(
new Text("to-")),
new Run(
new Text("replace")))));
return stream;
}
private static void ReplaceText(MemoryStream stream)
{
using WordprocessingDocument doc = WordprocessingDocument.Open(stream, true);
Body body = doc.MainDocumentPart.Document.Body;
IEnumerable<Paragraph> paras = body.Elements<Paragraph>();
foreach (Paragraph para in paras)
{
foreach (Run run in para.Elements<Run>())
{
foreach (Text text in run.Elements<Text>())
{
if (text.Text.Contains(ToReplace))
{
text.Text = text.Text.Replace(ToReplace, ReplaceWith);
run.AppendChild(new Break());
}
}
}
}
}
[Fact]
public void SimplisticTextReplacementOnlyWorksInSimpleCases()
{
// Arrange.
using MemoryStream stream = CreateWordprocessingDocument();
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, false))
{
Document document = wordDocument.MainDocumentPart.Document;
Paragraph firstParagraph = document.Descendants<Paragraph>().First();
Assert.Equal(ToReplace, firstParagraph.InnerText);
Assert.Contains(firstParagraph.Descendants<Text>(), t => t.Text == ToReplace);
Paragraph lastParagraph = document.Descendants<Paragraph>().Last();
Assert.Equal(ToReplace, lastParagraph.InnerText);
Assert.DoesNotContain(lastParagraph.Descendants<Text>(), t => t.Text == ToReplace);
}
// Act.
ReplaceText(stream);
// Assert.
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, false))
{
Document document = wordDocument.MainDocumentPart.Document;
Paragraph firstParagraph = document.Descendants<Paragraph>().First();
Assert.Equal(ReplaceWith, firstParagraph.InnerText);
Assert.Contains(firstParagraph.Descendants<Text>(), t => t.Text == ReplaceWith);
Paragraph lastParagraph = document.Descendants<Paragraph>().Last();
Assert.NotEqual(ReplaceWith, lastParagraph.InnerText);
Assert.DoesNotContain(lastParagraph.Descendants<Text>(), t => t.Text == ReplaceWith);
}
}
}
}

Changes are not getting saved - modify Track Changes Author in Header - OpenXML HeaderPart

Using C# in VS, I am trying to change the author name in track changes found in a word document header based on their dates. Using the debugger, it seems that the author's name is getting changed, but the document changes are not getting saved. I have included the 'headerPart.Header.Save()' line, which would presumably do trick, but no luck. I need help saving the document after the changes have been made - thanks!
private void changeRevAuthor(string docPath, string input_project_date)
{
using (Stream stream = System.IO.File.Open(docPath, FileMode.OpenOrCreate))
{
stream.Seek(0, SeekOrigin.End);
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
using (WordprocessingDocument document = WordprocessingDocument.Open(stream, true))
{
foreach (HeaderPart headerPart in document.MainDocumentPart.HeaderParts)
{
foreach (OpenXmlElement headerElement in headerPart.RootElement.Descendants())
{
OpenXmlElement children = headerPart.RootElement;
XElement xchildren = XElement.Parse(children.OuterXml);
var ychildren = xchildren.Descendants().Where(x => x.Attributes(w + "author").Count() > 0);
foreach (XElement descendant in ychildren)
{
var date = descendant.Attribute(w + "date").ToString().Substring(8, 10);
if (DateTime.Parse(date) > DateTime.Parse(input_project_date))
{
descendant.SetAttributeValue(w + "author", "new author name");
Debug.WriteLine("this is the new one" + descendant);
}
}
}
headerPart.Header.Save();
Debug.WriteLine("We got here");
}
document.Close();
}
}
}
Use MainDocumentPart save() method to save the changes in the document.
ie:document.MainDocumentPart.Document.Save();

ITextSharp build phrase from Html with list tags

I have a report that I'm trying to generate using iTextSharp that includes html text entered by the user using tinymce on my web page. I then have a report and I want to insert a phrase that uses their markup.
While basic markup such as bold and underline work, lists, indents, alignment do not. Any suggestions short of writing my own little html to pdf parser?
My code:
internal static Phrase GetPhraseFromHtml(string html, string fontName, int fontSize)
{
var returnPhrase = new Phrase();
html.Replace(Environment.NewLine, String.Empty);
//the string has to be well formated html in order to work and has to specify the font since
//specifying the font in the phrase overrides the formatting of the html tags.
string pTag = string.Format("<p style='font-size: {0}; font-family:{1}'>", fontSize, fontName);
if (html.StartsWith("<p>"))
{
html = html.Replace("<p>", pTag);
}
else
{
html = pTag + html + "</p>";
}
html
= "<html><body>"
+ html
+ "</body></html>";
using (StringWriter sw = new StringWriter())
{
using (System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(sw))
{
var xmlWorkerHandler = new XmlWorkerHandler();
//Bind a reader to our text
using (TextReader textReader = new StringReader(html))
{
//Parse
XMLWorkerHelper.GetInstance().ParseXHtml(xmlWorkerHandler, textReader);
}
var addPhrase = new Phrase();
var elementText = new StringBuilder();
bool firstElement = true;
//Loop through each element
foreach (var element in xmlWorkerHandler.elements)
{
if (firstElement)
{
firstElement = false;
}
else
{
addPhrase.Add(new Chunk("\n"));
}
//Loop through each chunk in each element
foreach (var chunk in element.Chunks)
{
addPhrase.Add(chunk);
}
returnPhrase.Add(addPhrase);
addPhrase = new Phrase();
}
return returnPhrase;
}
}
}

MailMerge with OpenXML

I have a sharepoint hosted application which contains a docx template file which has mailmerge fields like << Customer_Name >>.
It is a 1 Page document. I have to create a new docx file from this template which might contain multiple pages depending upon the number of customer. The content will be repeated and the merge fields has to be replaced with data from datatable for each page.
I tried using AltChunk but after using this method i cannot find and replace the text fields.
using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true))
{
template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
MainDocumentPart mainPart = template.MainDocumentPart;
for (int i = 0; i < dt.Rows.Count; i++)
{
if (dt.Rows[i][1].ToString() != "")
{
ReplaceText(mainPart, "«customer_Address»", dt.Rows[i][1].ToString());
string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 15);
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
chunk.FeedData(filestream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
mainPart.Document
.Body
.InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
mainPart.Document.Save();
}
}
I am using ReplaceText Method to Replace text from paragraph.
private static void ReplaceText(MainDocumentPart docPart, string match, string value)
{
var body = docPart.Document.Body;
foreach (var text in body.Descendants<Text>())
{
if (text.Text.Contains(match))
{
text.Text = text.Text.Replace(match, value);
}
}
}
This ReplaceText works fine for origional mainPart but does nothing for text added using AltChunk.
What would be easier way to generate multi page document in my case?

Categories

Resources