How to set or clear the Author in OpenXML SpeadsheetDocument - c#

When creating a spreadsheet with the OpenXML SpreadsheetDocument class in C#.Net, the Authors and Last saved by fields are set to "James Westgate".
How do I clear or overwrite James' name?
SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, true);
doc.PackageProperties.Creator = "sh";
...is not working for me.
Update:-
using System;
using System.Windows.Forms;
using System.IO;
using DocumentFormat.OpenXml.Extensions;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
namespace OpenXMLProps
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public MemoryStream Execute()
{
MemoryStream stream = SpreadsheetReader.Create();
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, true))
{
WorksheetPart worksheetPart = SpreadsheetReader.GetWorksheetPartByName(doc, "Sheet1");
WorksheetWriter writer = new WorksheetWriter(doc, worksheetPart);
doc.PackageProperties.Creator = "Finbar mahoolahan";
SpreadsheetWriter.Save(doc);
return new MemoryStream(stream.ToArray());
}
}
private void button1_Click(object sender, EventArgs e)
{
using (FileStream fs = new FileStream("excel_test.xlsx", FileMode.Create, FileAccess.Write))
{
MemoryStream excel_stream = Execute();
excel_stream.WriteTo(fs);
}
}
}
}

This works for me (after NuGet-ing in the OpenXml package):
using (var doc = SpreadsheetDocument.Open(#"C:\tmp\MyExcelFile.xlsx", true))
{
var props = doc.PackageProperties;
props.Creator = "Flydog57";
props.LastModifiedBy = "Flydog57";
doc.Save();
}
It even worked the first time I tried it! That's an unusual occurrence.

I believe (without looking at the code which is probably 8yrs old by now) that there is a base document which forms the template and this probably has my name associated with it. This is embedded as a resource in the dll.
I suggest trying to download the original SimpleOOXml source code from CodePlex and try modifying the document. You could recompile against a modern version of the OpenXML library too.

Related

itext7 pdfstream not compressed

I am trying to include an xml file into a pdf/a2 using itext7 and c#.
The xml has to be included into pdf names tree.
I was finally able to do it, the xml stream seems to be in the right names tree position.
There is still a problem, the stream has suppose to be compressed but is not, viewing the output pdf in a notepad you see the plain text.
It seems that the itext7 PdfStream is not able to do it, or at least, I am not able to compress it even setting compressionleve=9 - stream.SetCompressionLevel(9) in my code.
Anyone has a clue on how to do it.
Thank you very much.
Mauro
Here is my code:
using iText.Forms;
using iText.Kernel.Pdf;
using iText.Pdfa;
using iText.Layout.Element;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
namespace PdfXml
{
class Program
{
static void Main(string[] args)
{
string pdfIn = "\\xfar\\pdfin.pdf";
string pdfOut = "\\xfar\\pdfoutU.pdf";
string cdaIn = "\\xfar\\cda.xml";
StreamReader Reader = new StreamReader(cdaIn);
var content = new StringBuilder();
string line;
while (Reader.EndOfStream == false)
{
line = Reader.ReadLine();
content.AppendLine(line);
}
byte[] bytes = Encoding.ASCII.GetBytes(content.ToString());
PdfDocument pdfDoc = new PdfDocument(new PdfReader(pdfIn), new PdfWriter(pdfOut));
PdfStream stream = new PdfStream();;
PdfNameTree nameTree1 = pdfDoc.GetCatalog().GetNameTree(new PdfName("XFAResource"));
stream.SetCompressionLevel(9);
stream.SetData(bytes, true);
stream.Put(PdfName.Filter, PdfName.FlateDecode);
nameTree1.AddEntry("dataset", stream);
nameTree1.BuildTree();
nameTree1.SetModified();
Console.WriteLine("ok");
}
pdfDoc.Close();
}
}
}

Word found unreadable content error when opening file

I am facing an error "Word found unreadable content in abc.docx. Do you want to recover the content of this document?" while opening the Word (.docx) file.
I have tried with all the solutions given on the Internet but no success on this. Below is my code for writing the content into the stream.
private void test()
{
using (MemoryStream one = await db.DownloadFile("templates", "one.docx"))
{
using (MemoryStream two = await db.DownloadFile("templates", "two.docx"))
{
using (MemoryStream newStream = new MemoryStream())
{
one.CopyTo(newStream);
editingMemoryStream.Position = 0;
using (WordprocessingDocument mainDoc = WordprocessingDocument.Open(one, true))
{
using (WordprocessingDocument newDoc =
WordprocessingDocument.Open(newStream, true))
{
Generate(modal, new, main, report);
}
}
}
}
}
}
private void Generate(List<modal> mo, WordprocessingDocument new, MemoryStream report)
{
var main = new.MainDocumentPart;
modal = mo[0];
AddTableToBody(report, modal.table, mo);
}
public void AddTableToBody(MemoryStream temp, dailyReport,
MainDocumentPart main)
{
using (WordprocessingDocument newDoc = WordprocessingDocument.Open(editingMemoryStream, true))
{
WP.Body body= dailyReport.MainDocumentPart.Document.Body;
var main = dailyReport.MainDocumentPart;
//* some code is here*//
var clone = dailyReport.CloneNode(true);
main.Document.Body.AppendChild(new WP.Paragraph(new WP.Run(clone)));
main.Document.Save();
}
}
The file contains 2 tables with some labels.
Looking at your code, it looks like you are adding a w:body element (Body instance) to a w:r element (Run instance) in the following two lines of code:
var clone = dailyReport.CloneNode(true);
main.Document.Body.AppendChild(new WP.Paragraph(new WP.Run(clone)));
In the above excerpt, clone is a Body instance (w:body element) with all its child elements. I can only assume parent is the MainDocumentPart of some other WordprocessingDocument. You are appending a new Paragraph (w:p) with one w:r (Run) and one w:body (Body) with whatever children the latter has. This is invalid Open XML and most probably the reason why Word complains.

Embed html within a table or at specific location in a docx document

I'm trying to add HTML content to DOCX file using OpenXML altchunk approach using C#. The below sample code works fine and appends the HTML content to the end of the document. My requirement is to add HTML content at a specific place in the document, like inside a table cell or inside a paragraph, or search and replace a specific string with an HTML string or placeholders marked using content controls. Can you please point me to some sample example or share few suggestions. Please let me know if you need more info.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
using OpenXmlPowerTools;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
using System.Xml;
namespace Docg2
{
class Program
{
static void Main(string[] args)
{
testaltchunk();
}
public static void testaltchunk()
{
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
using (WordprocessingDocument myDoc = WordprocessingDocument.Open("../../Test3.docx", true))
{
string html =
#"<html>
<head/>
<body>
<h1>Html Heading</h1>
<p>This is an html document in a string literal.</p>
</body>
</html>";
string altChunkId = "AltChunkId1";
MainDocumentPart mainPart = myDoc.MainDocumentPart;
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart("application/xhtml+xml", altChunkId);
using (Stream chunkStream = chunk.GetStream(FileMode.Create, FileAccess.Write))
using (StreamWriter stringStream = new StreamWriter(chunkStream))
stringStream.Write(html);
XElement altChunk = new XElement(w + "altChunk", new XAttribute(r + "id", altChunkId));
XDocument mainDocumentXDoc = GetXDocument(myDoc);
mainDocumentXDoc.Root
.Element(w + "body")
.Elements(w + "p")
.Last()
.AddAfterSelf(altChunk);
SaveXDocument(myDoc, mainDocumentXDoc);
}
}
private static void SaveXDocument(WordprocessingDocument myDoc, XDocument mainDocumentXDoc)
{
// Serialize the XDocument back into the part
using (var str = myDoc.MainDocumentPart.GetStream(FileMode.Create, FileAccess.Write))
using (var xw = XmlWriter.Create(str))
mainDocumentXDoc.Save(xw);
}
private static XDocument GetXDocument(WordprocessingDocument myDoc)
{
// Load the main document part into an XDocument
XDocument mainDocumentXDoc;
using (var str = myDoc.MainDocumentPart.GetStream())
using (var xr = XmlReader.Create(str))
mainDocumentXDoc = XDocument.Load(xr);
return mainDocumentXDoc;
}
}
}
To expand on my comment a little bit: You really shouldn't be manipulating the document XML yourself. You lose all the benefits of using OpenXML in the first place. Thus, your code could be re-written like this:
static void Main(string[] args)
{
using (WordprocessingDocument myDoc = WordprocessingDocument.Open("../../Test3.docx", true))
{
string html =
#"<html>
<head/>
<body>
<h1>Html Heading</h1>
<p>This is an html document in a string literal.</p>
</body>
</html>";
string altChunkId = "AltChunkId1";
MainDocumentPart mainPart = myDoc.MainDocumentPart;
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart("application/xhtml+xml", altChunkId);
using (Stream chunkStream = chunk.GetStream(FileMode.Create, FileAccess.Write))
using (StreamWriter stringStream = new StreamWriter(chunkStream))
stringStream.Write(html);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
// this inserts altChunk after the last Paragraph
mainPart.Document.Body
.InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
mainPart.Document.Save();
}
}
Now, it becomes clear that you can insert your AltChunk after, or before, or inside any element in the document, as long as you can find the element. That part will depend on what you're searching for.
If you're searching for a specific table, then search for a DocumentFormat.OpenXml.Wordprocessing.Table etc. Here is one example of how to search for a specific table in a document: Find a specific Table (after a bookmark) in open xml
Here's an example of replacing a content control https://msdn.microsoft.com/en-us/library/cc197932(v=office.12).aspx

Binary Serialization of an Observable Collection -- Saving, Loading

I am having a problems creating binary serialization for my observable collection of Contacts Objects. The Person Object contains the firstname,lastname, and age properties.
The collection is called NewAccountList.
I want to be able to persist my collection data by saving it to a file. This action currently occurs when the save button is clicked, but it does xml serialization instead of binary serialization.
private void MenuItem_Click_2(object sender, RoutedEventArgs e)
{
// Create OpenFileDialog
Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
XmlSerializer xs = new XmlSerializer(typeof(ObservableCollection));
sfd.Filter = "XML files (.xml)|.xml";
// Display OpenFileDialog by calling ShowDialog method
Nullable<bool> result = sfd.ShowDialog();
try
{
using (StreamWriter wr = new StreamWriter("SavedAccounts.xml"))
{
xs.Serialize(wr, NewAccountList);
}
}
catch
{}
}
Would anybody be able to give me a good example of how to save a collection of objects?
full code example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (FileStream fs = File.Create("data.hffgfh"))
{
bf.Serialize(fs, 123456);
}
}
}
}
output:
Try changing .xml to .bin. That should fix your problem

How can I return a stream rather than writing to disk?

I am using OpenXML SDK.
The OpenXML SDK creates a method called CreatePackage as such:
public void CreatePackage(string filePath)
{
using (SpreadsheetDocument package = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook))
{
CreateParts(package);
}
}
I call it from my program as follows which will create the Excel file to a given path:
gc.CreatePackage(excelFilePath);
Process.Start(_excelFilePath);
I am not sure how to tweak the code such that it gives back a Stream which shows the Excel file vs having it create the file on disk.
According to the documentation for SpreadsheetDocument.Create there are multiple overloads, one of which takes a Stream.
so change your code to:
public void CreatePackage(Stream stream)
{
using (SpreadsheetDocument package = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook))
{
CreateParts(package);
}
}
And then call it with any valid Stream, for example:
using(var memoryStream = new MemoryStream())
{
CreatePackage(memoryStream);
// do something with memoryStream
}

Categories

Resources