2012-06-07 14 views
5

Tôi đang cố gắng tạo bảng tính trong .NET. Trình quản lý của tôi sẽ mở trên bảng tính khi iPad ra khỏi văn phòng.Bảng tính OpenXML được tạo trong .NET sẽ không mở trong iPad

Bảng tính mở tốt trên một máy tính Windows, nhưng khi cố gắng để mở trên iPad nó nói "Có lỗi xảy ra trong khi đọc tài liệu" (như vậy hữu ích!)

Bằng việc sử dụng "So sánh" tính năng trên OpenXML SDK Năng suất công cụ với một tài liệu mà hiện mở trên iPad, và bằng cách làm một số chỉnh sửa thủ công các tệp XML của tài liệu bị lỗi trong notepad tôi đã thu hẹp nó xuống tệp xl/_rels/workbook.xml.rels lưu trữ các mối quan hệ của các phần trong sổ làm việc.

Đây là mã tôi đang sử dụng để tạo ra các WorkbookPart và tham khảo

WorkbookPart workbookPart1 = document.AddWorkbookPart(); 

    WorkbookStylesPart workbookStylesPart1 = workbookPart1.AddNewPart<WorkbookStylesPart>("rId3"); 
    ThemePart themePart1 = workbookPart1.AddNewPart<ThemePart>("rId2"); 
    WorksheetPart worksheetPart1 = workbookPart1.AddNewPart<WorksheetPart>("rId1"); 

Mã của tôi tạo ra đầu ra sau đây, mà không mở trên 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> 

Nếu tôi thay đổi giá trị của thuộc tính Target để sử dụng đường dẫn tham chiếu tương đối, đưa ra kết quả sau, sau đó mở trên 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> 

Vì vậy, câu hỏi là:
Làm thế nào để thay đổi mã NET của tôi để nó ra phiên bản thứ hai của XML, với đường dẫn tương đối.

Tất cả sự giúp đỡ đã được biết ơn!

+0

Điều này có vẻ giống như câu hỏi "cách sử dụng" hơn câu hỏi lập trình, nhưng dù sao, với ứng dụng nào trên iPad bạn đang cố mở bảng tính? –

+0

Xin lỗi, tôi không hiểu ý của bạn về "cách sử dụng" so với lập trình nhưng cảm ơn bạn đã trả lời tôi. Tôi chỉ gửi email cho nó một mở nó trực tiếp từ ứng dụng thư trên ipad. – Jen

+0

Tôi có cùng một vấn đề, nhưng không có tệp quan hệ nào trong tài liệu cũng như bất kỳ thuộc tính Target nào ở bất kỳ đâu! – simbolo

Trả lời

0

Bạn có thể thử để xác nhận bảng OpenXML khi nó đã được tạo ra:

using System; 
using System.Collections.Generic; 
using DocumentFormat.OpenXml.Packaging; 
using DocumentFormat.OpenXml.Validation; 

using (OpenXmlPackage document = SpreadsheetDocument.Open(spreadsheetPathToValidate, false)) 
{ 
    var validator = new OpenXmlValidator(); 
    IEnumerable<ValidationErrorInfo> errors = validator.Validate(document); 
    foreach (ValidationErrorInfo info in errors) 
    { 
     try 
     { 
      Console.WriteLine("Validation information: {0} {1} in {2} part (path {3}): {4}", 
         info.ErrorType, 
         info.Node.GetType().Name, 
         info.Part.Uri, 
         info.Path.XPath, 
         info.Description); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Validation failed: {0}", ex); 
     } 
    } 
} 

Hy vọng rằng sẽ giúp,

+0

Nó xác nhận thành công mặc dù. Nó cũng xác nhận thành công nếu tôi sử dụng công cụ xác thực trong công cụ năng suất SDK. Ngoài ra, tôi cần một phương pháp để thực sự thay đổi nó - tôi có thể thấy trường URI cho mối quan hệ trong mã nhưng nó chỉ đọc. – Jen

2

câu trả lời gửi một pdf Comradsky là một ý tưởng tốt, nhưng trong trường hợp ai cần để có thể giải quyết điều này, tôi đã đưa ra một giải pháp. Tôi biết đây là một hack khủng khiếp nhưng nó hoạt động và tôi đã dành nhiều giờ cố gắng tìm một cách để làm điều đó "hợp pháp" không có kết quả.

Nó liên quan đến việc mở tệp .rels và chỉnh sửa trực tiếp xml trong tệp sau khi tài liệu đã bị đóng.

public static void MakeRelativePaths(string filepath) 
    { 
     // Get the namespace strings 
     const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"; 
     const string relationshipSchema = "http://schemas.openxmlformats.org/package/2006/relationships"; 

     string documentUri = null; 
     string documentDirectory = null; 
     string documentName = null; 

     Uri relDocUri = null; 

     XName targetAttributeName = null; 
     string targetValue = null; 

     // Open the package 
     using (Package xlPackage = Package.Open(filepath, FileMode.Open, FileAccess.ReadWrite)) 
     { 
      // Get the directory and filename of the main document part (e.g. /xl/workbook.xml). 
      foreach (System.IO.Packaging.PackageRelationship relationship in xlPackage.GetRelationshipsByType(documentRelationshipType)) 
      { 
       documentUri = relationship.TargetUri.ToString(); 

       documentName = System.IO.Path.GetFileName(documentUri); 
       documentDirectory = documentUri.Substring(0, documentUri.Length - documentName.Length); 

       // There should only be document part in the package, but break out anyway. 
       break; 
      } 

      // Load the relationship document 
      relDocUri = new Uri(documentDirectory + "_rels/" + documentName + ".rels", UriKind.Relative); 
      XDocument relDoc = XDocument.Load(xlPackage.GetPart(relDocUri).GetStream()); 

      // Loop through all of the relationship nodes 
      targetAttributeName = XName.Get("Target"); 
      foreach (XElement relNode in relDoc.Elements(XName.Get("Relationships", relationshipSchema)).Elements(XName.Get("Relationship", relationshipSchema))) 
      { 
       // Edit the value of the Target attribute 
       targetValue = relNode.Attribute(targetAttributeName).Value; 

       if (targetValue.StartsWith(documentDirectory)) 
        targetValue = targetValue.Substring(documentDirectory.Length); 

       relNode.Attribute(targetAttributeName).Value = targetValue; 
      } 

      // Save the document 
      relDoc.Save(xlPackage.GetPart(relDocUri).GetStream()); 
     } 
    } 
+0

Tôi gặp vấn đề tương tự - và tôi đã thử thực hiện điều này, nhưng tôi đang sử dụng tài liệu trong luồng chứ không phải IO. Không may mắn nhận được nó để đi. Mã của bạn chạy và tôi đã mong đợi nó hoạt động sau khi so sánh các tệp được trích xuất. Nếu bạn có thể giúp đỡ, nó sẽ được đánh giá cao. – JonK

1

Tôi cũng đã đấu tranh với một vấn đề tương tự như vậy trong một thời gian. Cuối cùng tôi đã đưa ra một giải pháp hoạt động. Đây là mã tôi đã viết để khắc phục sự cố

 // Add a new worksheet part to the workbook. 
     WorksheetPart newWorksheetPart = _document.WorkbookPart.AddNewPart<WorksheetPart>(); 
     newWorksheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet(new SheetData()); 

     Sheets sheets = _document.WorkbookPart.Workbook.GetFirstChild<Sheets>(); 
     string relationshipId = _document.WorkbookPart.GetIdOfPart(newWorksheetPart); 

     //This bit is required for iPad to be able to read the sheets inside the xlsx file. The file will still work fine in Excel 
     string relationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"; 
     _document.Package.GetPart(_document.WorkbookPart.Uri).CreateRelationship(new Uri(newWorksheetPart.Uri.OriginalString.Replace("/xl/", String.Empty).Trim(), UriKind.Relative), TargetMode.Internal, relationshipType); 
     _document.Package.GetPart(_document.WorkbookPart.Uri).DeleteRelationship(relationshipId); 
     PackageRelationshipCollection sheetRelationships = _document.Package.GetPart(_document.WorkbookPart.Uri).GetRelationshipsByType(relationshipType); 

     relationshipId = sheetRelationships.Where(f => f.TargetUri.OriginalString == newWorksheetPart.Uri.OriginalString.Replace("/xl/", String.Empty).Trim()).Single().Id; 


     // Get a unique ID for the new sheet. 
     uint sheetId = 1; 
     if (sheets.Elements<Sheet>().Count() > 0) 
      sheetId = sheets.Elements<Sheet>().Max(s => s.SheetId.Value) + 1; 

     // Append the new worksheet and associate it with the workbook. 
     Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName }; 
     sheets.Append(sheet); 

     _worksheets.Add(new Worksheet(newWorksheetPart.Worksheet, sheetId)); 

_document và _worksheets, là các biến riêng tư trong lớp giải pháp của tôi.

+0

Không hoạt động cho tôi: ( – Renan

+0

điều này đang hoạt động! Cuối cùng! (Y) –

5

Tôi đã dành rất nhiều thời gian nghiên cứu và nghĩ rằng tôi muốn chia sẻ kết quả của mình. Có vẻ như OpenXML đang làm hai việc. 1. Tệp content_types.xml thiếu mục nhập cho sổ làm việc 2. Tệp xl/_rels/workbook.xml.rels đang sử dụng đường dẫn tương đối đầy đủ.

Excel tự mở tệp nhưng tôi đã thử các ứng dụng khác nhau trên iPad và tất cả đều không thành công. Vì vậy, tôi đã phải tự sửa các tập tin bản thân mình bằng cách sử dụng mã sau đây.Nó giả định toàn bộ nội dung của tệp được truyền vào dưới dạng luồng và sử dụng DotNetZip để mở và thao tác. Hy vọng mã này sẽ giúp người khác!

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; 
     } 
    } 
Các vấn đề liên quan