Open XML: We found a problem with some content in 'myfile.xlsx' - c#

I am creating an Excel file using the Open XML SDK.
Worksheet newWs = new Worksheet()
{
MCAttributes = new MarkupCompatibilityAttributes() { Ignorable = "x14ac" }
};
When I add a SheetViews instance as follows,
SheetViews sheetViews = new SheetViews();
SheetView sheetView = new SheetView();
Selection selection = new Selection() { ActiveCell = "B1" };
sheetView.Append(selection);
sheetViews.Append(sheetView);
newWs.Append(sheetViews);
I get an error as shown below (and also ActiveCell is not working):
We found a problem with some content in 'myfile.xlsx'. Do you want us
to try to recover as much as we can? If you trust the source of this
workbook, click Yes.

This was issue with ordering of the excel xml elements.
I had applied sheetviews after applying styles.
Which openxml didn't like.
So I get to know about this by using XML SDK productivity tool. Which helped making correct order.

Related

OpenXML SDK C# - Shared Formula corrupts my Excel file

I am trying to insert a Shared Formula into an existing Excel sheet. every time I open the finished Excel, it shows me an error and fixes the Excel. I have the code from OpenXML Productivity Tools. All other formulas work without problems ...
var cellFormula141 = new CellFormula
{
FormulaType = CellFormulaValues.Shared,
Reference = $"J{rowIndex}",
SharedIndex = 0U,
Text = $"CONCATENATE(MONTH(I{rowIndex}),\"/\",YEAR(I{rowIndex}))"
};
var cellValue215 = new CellValue
{
Text = ""
};
cell372.Append(cellFormula141);
cell372.Append(cellValue215);
Every time I open the excel it is fixed and the formula is gone.

How to set active sheet with Open XML SDK 2.5

using the example here How to Copy a Worksheet within a Workbook
I have successfully been able to clone/copy sheets in my excel file, however when I open the excel the 2nd sheet is the active(visible) sheet. I haven't been able to locate a property that could do thins.....Is there any way to specify what sheet is active?
I've tried to force it by opening and editing the first sheet in the file thinking it was the last edited sheet that was active but that didn't work either.
any help would be great. TIA
update: looking at the workbook.xml created when renaming the .xlsx to .zip I came accross the 'activeTab' property. made a quick change to my code and seems to work just fine
public void SetFirstSheetInFocus(String xlsxFile)
{
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(xlsxFile, true))
{
//Get a reference to access the main Workbook part, which contains all references
WorkbookPart _workbookPart = spreadSheet.WorkbookPart;
if (_workbookPart != null)
{
WorkbookView _workbookView = spreadSheet.WorkbookPart.Workbook.BookViews.ChildElements.First<WorkbookView>();
if (_workbookView != null)
{
_workbookView.ActiveTab = 0; // 0 for first or whatever tab you want to use
}
// Save the workbook.
_workbookPart.Workbook.Save();
}
}
}
If the name of your sheet is in the variable
sheetName
you can set the sheet with that name active like this:
using (var spreadsheetDoc = SpreadsheetDocument.Open(emptyHIPTemplatePath, true /* isEditable */, new OpenSettings { AutoSave = false }))
{
var workbookPart = spreadsheetDoc.WorkbookPart;
var workBook = spreadsheetDoc.WorkbookPart.Workbook;
var sheet = workBook.Descendants<Sheet>().FirstOrDefault(s => s.Name == sheetName);
var sheetIndex = workBook.Descendants<Sheet>().ToList().IndexOf(sheet);
var workBookView = workBook.Descendants<WorkbookView>().First();
workBookView.ActiveTab = Convert.ToUInt32(sheetIndex);
...
workBook.Save();
}
From Vincent Tan's book:
The SheetId property doesn't determine the order. The order of
appending the Sheet classes to the Sheets class, does.
When you add a sheet, it gets the next index, but a single sheet does not have an index. OpenXML gives it an index when you are done adding sheets. Again, from Vincent Tan's book:
Let's say you have 3 worksheets named Sheet1, Sheet2 and Sheet3.
However, when you appended the corresponding Sheet classes, you did it
as Sheet2, Sheet3 and Sheet1, in that order.

ITextSharp PDFTemplate FormFlattening removes filled data

I am porting an existing app from Java to C#. The original app used the IText library to fill PDF form templates and save them as new PDF's. My C# code (example) below:
string templateFilename = #"C:\Templates\test.pdf";
string outputFilename = #"C:\Output\demo.pdf";
using (var existingFileStream = new FileStream(templateFilename, FileMode.Open))
{
using (var newFileStream = new FileStream(outputFilename, FileMode.Create))
{
var pdfReader = new PdfReader(existingFileStream);
var stamper = new PdfStamper(pdfReader, newFileStream);
var form = stamper.AcroFields;
var fieldKeys = form.Fields.Keys;
foreach (string fieldKey in fieldKeys)
{
form.SetField(fieldKey, "REPLACED!");
}
stamper.FormFlattening = true;
stamper.Close();
pdfReader.Close();
}
}
All works well only if I ommit the
stamper.FormFlattening = true;
line, but then the forms are visible as...forms.
When I add the this line, any values set to the form fields are lost, resulting in a blank form. I would really appreciate any advice.
Most likely you can resolve this when using iTextSharp 5.4.4 (or later) by forcing iTextSharp to generate appearances for the form fields. In your example code:
var form = stamper.AcroFields;
form.GenerateAppearances = true;
Resolved the issue by using a previous version of ITextSharp (5.4.3). Not sure what the cause is though...
I found a working solution for this for any och the newer iTextSharp.
The way we do it was:
1- Create a copy of the pdf temmplate.
2- populate the copy with data.
3- FormFlatten = true and setFullCompression
4- Combine some of the PDFs to a new document.
5- Move the new combined document and then remove the temp.
This way we got the issue with removed input and if we skipped the "formflatten" it looked ok.
However when we moved the "FormFlatten = true" from step 3 and added it as a seperate step after the moving etc was complete, it worked perfectly.
Hope I explained somewhat ok :)
In your PDF File, change the property to Visible, the Default value is Visible but not printable.

Documentformat.openxml - create word document with default styles

I want the word document created to use the default styles in Word, so the user can change the styles using the built in themes.
I have tried using:
var paragraph = new Paragraph();
var run = new Run();
run.Append(new Text(text));
paragraph.Append(run);
var header = new Header();
header.Append(paragraph);
But its styled as "Normal".
So, how do i make it become "Heading 1" when i open the document in Word?
If you're like me and you found this post because you were trying to build documents using OpenXML with the default styles "Heading 1", "Heading 2", "Title", etc. you get when you use Microsoft Word I found the solution after a few hours.
First I tried to find the styles in the normal template "Normal.dotm". This is not where the styles are stored, you are looking in the wrong place. The default styles are actually defined in a "Default.dotx" file in a directory named QuickStyles.
The path is going to change depending on your version and your OS. For me I found the dotx at "C:\Program Files (x86)\Microsoft Office\Office14\1033\QuickStyles".
I found some code from this blog post to create and modify a document from a template:
void CreateWordDocumentUsingMSWordStyles(string outputPath, string templatePath)
{
// create a copy of the template and open the copy
System.IO.File.Copy(templatePath, outputPath, true);
using (var document = WordprocessingDocument.Open(outputPath, true))
{
document.ChangeDocumentType(WordprocessingDocumentType.Document);
var mainPart = document.MainDocumentPart;
var settings = mainPart.DocumentSettingsPart;
var templateRelationship = new AttachedTemplate { Id = "relationId1" };
settings.Settings.Append(templateRelationship);
var templateUri = new Uri("c:\\anything.dotx", UriKind.Absolute); // you can put any path you like and the document styles still work
settings.AddExternalRelationship("http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate", templateUri, templateRelationship.Id);
// using Title as it would appear in Microsoft Word
var paragraphProps = new ParagraphProperties();
paragraphProps.ParagraphStyleId = new ParagraphStyleId { Val = "Title" };
// add some text with the "Title" style from the "Default" style set supplied by Microsoft Word
var run = new Run();
run.Append(new Text("My Title!"));
var paragraph = new Paragraph();
paragraph.Append(paragraphProps);
paragraph.Append(run);
mainPart.Document.Body.Append(paragraph);
mainPart.Document.Save();
}
}
Simply call this method with templatePath pointing to your Default.dotx file and you will be able to use the default styles as they appear in Microsoft Word.
var path = System.IO.Path.GetTempFileName();
CreateWordDocumentUsingMSWordStyles(path, "C:\\Program Files (x86)\\Microsoft Office\\Office14\\1033\\QuickStyles\\Default.dotx");
This does let the user change "Style Sets" in Word once they open the document as per the original question.

Creating cell comments in an Excel Spreadsheet with OpenXML SDK

I'm trying to add comments to cells in an Excel 2007 spreadsheet. I'm using the OpenXml SDK 2.0 to do so.
My use case is this:
I've created a template Excel file that I copy and use that as my starting point, rather than create an OpenXML document from scratch. My template file has a comment in cell A1 so that Excel has already created a WorksheetCommentPart for me.
Now my problem is that when I add Comment nodes to the Comments part the spreadsheet doesn't load and Excel asks if I want to recover.
What really bothers me is that my original comment in A1 is still there, but any comments I added programmatically are gone!
Here's the code I'm working with:
using (MemoryStream spreadsheetStream = new MemoryStream())
{
GetGradebookSpreadsheetTemplate(spreadsheetStream);
using (SpreadsheetDocument spDoc = SpreadsheetDocument.Open(spreadsheetStream, true))
{
WorkbookPart wbPart = spDoc.WorkbookPart;
WorksheetPart wsPart = wbPart.WorksheetParts.First();
SheetData sheet = wsPart.Worksheet.GetFirstChild<SheetData>();
Comments comments = wsPart.WorksheetCommentsPart.Comments;
comments.Descendants<Author>().First().Text = string.Format("{0}, {1}", instructor.LastName, instructor.FirstName);
comments.Descendants<Text>().First().Text = string.Format("{0}, {1}", instructor.LastName, instructor.FirstName);
List<DefinedName> definedNames = new List<DefinedName>();
definedNames.Add(CreateDefinedName("COLWeb_Gradebook", sheet.NamespaceURI, "Gradebook", "1", "A"));
uint index = 4;
foreach (User u in users)
CreateUserDataRow(index++, definedNames, comments.CommentList, sheet, u, coursesForUsers[u], assignments, submissions[u]);
Cell lastCell = sheet.Descendants<Cell>().Last();
OpenXmlElement dimensionsElement = wsPart.Worksheet.Elements().Where(x => x.LocalName == "dimension").First();
dimensionsElement.SetAttribute(new OpenXmlAttribute("ref", null, "A1:" + lastCell.CellReference));
comments.Save();
wsPart.Worksheet.Save();
wbPart.Workbook.Save();
}
return spreadsheetStream.ToArray();
}
And "CreateUserDataRow" creates a new row, but the relevant part is (where "comment" is my comment string and "c" is my Cell that I want to create the comment about):
if (!string.IsNullOrEmpty(comment))
{
List<OpenXmlElement> runs = new List<OpenXmlElement>();
foreach (string row in comment.Split(new string[] { "<p>", "</p>" }, StringSplitOptions.RemoveEmptyEntries))
{
string trimmed = row.Trim();
if (!string.IsNullOrEmpty(trimmed))
{
string escaped = System.Security.SecurityElement.Escape(trimmed);
runs.Add(new Run(new RunProperties(), new Text(escaped)));
}
}
Comment commentCell = new Comment();
commentCell.Reference = c.CellReference;
commentCell.AuthorId = 0;
commentCell.AppendChild(new CommentText(runs));
comments.AppendChild(commentCell);
}
Now as far as my eye can see, and KDiff3 for that matter, my files are pretty much identical to the files that would be output if I were to open Excel and put the comments into the cells by hand in Excel.
Does anyone have a good example of attaching a comment to a cell with OpenXml? Is there something I should know about maybe a relationship? Does it have something to do with using an Excel file that I created and then I'm using as a template (maybe some dimensions aren't set)?
Thanks for any help I can get.
Unfortunately, it is not that simple.
Cell comments also have a graphics object which is in a VML drawing part. VML is a cryptic legacy specification and is not in the approved ECMA standard. You can find documentation on it in Microsoft's Open XML documents, but it is not pretty. Hopefully Microsoft will address this in Excel 14 by adding full cell comment support as well as support for controls which are also written to VML.
Having said that, I have not used the Open XML SDK and I cannot say whether or not it is possible to add comments with it. I just thought this might help get you pointed in the right direction.
There appears to be a code sample at http://openxmldeveloper.org/forums/thread/7396.aspx which shows how to create the requisite VML Drawing. I'm trying this code now, and seem to have progressed, though I'm still getting some sort of unspecified error in which Excel decides to drop the comments before opening...

Categories