在.NET中创建的OpenXML US preadsheet不会在iPad的开 [英] OpenXML spreadsheet created in .NET won't open in iPad
问题描述
我想产生的preadsheet在.NET这将是打开的,我的经理在他的iPad时,他不在办公室。
I am trying to generate a spreadsheet in .NET which will be opened by my manager on his iPad when he's out of the office.
在S preadsheet打开罚款在Windows PC上,而是试图打开在iPad上时,它说当读取文件时出错(非常有用!)
The spreadsheet opens fine on a Windows PC, but when trying to open on the iPad it says "An error occurred while reading the document" (so useful!)
通过使用比较功能的OpenXML的SDK生产力工具与文档的不打开iPad上,并通过执行错误的文档的XML文件中的一些手工编辑在记事本中我已经收窄下来到文件的 XL / _rels / workbook.xml.rels 存储部件的工作簿中的关系。
By using the "Compare" feature on the OpenXML SDK Productivity tool with a document that does open on the iPad, and by doing some manual editing of the faulty document's XML files in notepad I have narrowed it down to the file xl/_rels/workbook.xml.rels which stores the relationships of the parts in the workbook.
这是在code我使用生成WorkbookPart和引用
This is the code I am using to generate the WorkbookPart and references
WorkbookPart workbookPart1 = document.AddWorkbookPart();
WorkbookStylesPart workbookStylesPart1 = workbookPart1.AddNewPart<WorkbookStylesPart>("rId3");
ThemePart themePart1 = workbookPart1.AddNewPart<ThemePart>("rId2");
WorksheetPart worksheetPart1 = workbookPart1.AddNewPart<WorksheetPart>("rId1");
我的code产生如下的输出,这并不在iPad上打开。
My code generates the following output, which does not open on the iPad.
<?xml version="1.0" encoding="utf-8" ?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="/xl/styles.xml" Id="rId3" />
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="/xl/theme/theme.xml" Id="rId2" />
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="/xl/worksheets/sheet.xml" Id="rId1" />
</Relationships>
如果我更改目标属性的值使用相对参考路径,让下面的输出,那么它在iPad上打开。
If I change the value of the Target attributes to use a relative reference path, giving the following output, then it does open on the iPad.
<?xml version="1.0" encoding="utf-8" ?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml" Id="rId3" />
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme.xml" Id="rId2" />
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet.xml" Id="rId1" />
</Relationships>
所以,问题是:
如何更改我的.NET code,使其输出的XML的第二个版本,用相对路径。
So the question is:
How do I change my .NET code so that it outputs the second version of the XML, with relative paths.
所有帮助感激地接受!
推荐答案
我已经花了很多时间研究这个,以为我会分享我的结果。看来,OpenXML的做了两件事。 1. content_types.xml文件丢失工作簿中的条目 2. XL / _rels / workbook.xml.rels是使用fullly相对路径的文件。
I've spent a lot of time researching this and thought I'd share my results. It appears that OpenXML is doing two things. 1. The content_types.xml file is missing an entry for the workbook 2. The xl/_rels/workbook.xml.rels file is using a fullly relative path.
Excel中打开自己的文件很好,但我试过在iPad上的应用程序不同,他们都失败。所以,我已经用下面的code手动修复文件自己。它假定该文件的全部内容通过在作为流并使用DotNetZip打开和操纵。希望这code可以帮助别人!
Excel itself opens the file fine but I've tried various apps on the iPad and they all fail. So I've had to manually fix the files myself using the following code. It assumes the entire content of the file is passed in as a stream and uses DotNetZip to open and manipulate. Hope this code helps others!
private Stream ApplyOpenXmlFix(Stream input)
{
const string RELS_FILE = @"xl/_rels/workbook.xml.rels";
const string RELATIONSHIP_ELEMENT = "Relationship";
const string CONTENT_TYPE_FILE = @"[Content_Types].xml";
const string XL_WORKBOOK_XML = "/xl/workbook.xml";
const string TARGET_ATTRIBUTE = "Target";
const string SUPERFLUOUS_PATH = "/xl/";
const string OVERRIDE_ELEMENT = "Override";
const string PARTNAME_ATTRIBUTE = "PartName";
const string CONTENTTYPE_ATTRIBUTE = "ContentType";
const string CONTENTTYPE_VALUE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
XNamespace contentTypesNamespace = "http://schemas.openxmlformats.org/package/2006/content-types";
XNamespace relsNamespace = "http://schemas.openxmlformats.org/package/2006/relationships";
XDocument xlDocument;
MemoryStream memWriter;
try
{
input.Seek(0, SeekOrigin.Begin);
ZipFile zip = ZipFile.Read(input);
//First we fix the workbook relations file
var workbookRelations = zip.Entries.Where(e => e.FileName == RELS_FILE).Single();
xlDocument = XDocument.Load(workbookRelations.OpenReader());
//Remove the /xl/ relative path from all target attributes
foreach (var relationship in xlDocument.Root.Elements(relsNamespace + RELATIONSHIP_ELEMENT))
{
var target = relationship.Attribute(TARGET_ATTRIBUTE);
if (target != null && target.Value.StartsWith(SUPERFLUOUS_PATH))
{
target.Value = target.Value.Substring(SUPERFLUOUS_PATH.Length);
}
}
//Replace the content in the source zip file
memWriter = new MemoryStream();
xlDocument.Save(memWriter, SaveOptions.DisableFormatting);
memWriter.Seek(0, SeekOrigin.Begin);
zip.UpdateEntry(RELS_FILE, memWriter);
//Now we fix the content types XML file
var contentTypeEntry = zip.Entries.Where(e => e.FileName == CONTENT_TYPE_FILE).Single();
xlDocument = XDocument.Load(contentTypeEntry.OpenReader());
if (!xlDocument.Root.Elements().Any(e =>
e.Name == contentTypesNamespace + OVERRIDE_ELEMENT &&
e.Attribute(PARTNAME_ATTRIBUTE) != null &&
e.Attribute(PARTNAME_ATTRIBUTE).Value == XL_WORKBOOK_XML))
{
//Add in the missing element
var overrideElement = new XElement(
contentTypesNamespace + OVERRIDE_ELEMENT,
new XAttribute(PARTNAME_ATTRIBUTE, XL_WORKBOOK_XML),
new XAttribute(CONTENTTYPE_ATTRIBUTE, CONTENTTYPE_VALUE));
xlDocument.Root.Add(overrideElement);
//Replace the content
memWriter = new MemoryStream();
xlDocument.Save(memWriter, SaveOptions.DisableFormatting);
memWriter.Seek(0, SeekOrigin.Begin);
zip.UpdateEntry(CONTENT_TYPE_FILE, memWriter);
}
Stream output = new MemoryStream();
//Save file
zip.Save(output);
return output;
}
catch
{
//Just in case it fails, return the original document
return input;
}
}
这篇关于在.NET中创建的OpenXML US preadsheet不会在iPad的开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!