2013-08-06 41 views
16

Tôi đang cố gắng sử dụng thư viện OpenXML 2.5 của Microsoft để tạo một tài liệu OpenXML. Mọi thứ hoạt động tốt, cho đến khi tôi cố gắng chèn một chuỗi HTML vào tài liệu của mình. Tôi đã lùng sục các trang web và đây là những gì tôi đã đưa ra cho đến nay (snipped để chỉ phần Tôi gặp rắc rối với):Thêm chuỗi HTML vào tài liệu OpenXML (* .docx)

Paragraph paragraph = new Paragraph(); 
Run run = new Run(); 

string altChunkId = "id1"; 
AlternativeFormatImportPart chunk = 
     document.MainDocumentPart.AddAlternativeFormatImportPart(
      AlternativeFormatImportPartType.Html, altChunkId); 
chunk.FeedData(new MemoryStream(Encoding.UTF8.GetBytes(ioi.Text))); 
AltChunk altChunk = new AltChunk { Id = altChunkId }; 

run.AppendChild(new Break()); 

paragraph.AppendChild(run); 
body.AppendChild(paragraph); 

Rõ ràng, tôi đã không thực sự thêm altChunk trong ví dụ này, nhưng tôi đã cố gắng thêm nó ở khắp mọi nơi - để chạy, đoạn văn, nội dung, v.v. Trong mọi trường hợp, tôi không thể mở tệp docx trong Word 2010.

Điều này khiến tôi hơi hấp dẫn vì có vẻ như nó nên được đơn giản (tôi sẽ thừa nhận rằng tôi không hoàn toàn hiểu được điều "AltChunk"). Sẽ đánh giá cao sự giúp đỡ nào.

Lưu ý phụ: Một điều tôi đã thấy thú vị và tôi không biết đó có phải là sự cố hay không, là this response cho biết AltChunk hỏng tệp khi làm việc từ MemoryStream. Ai có thể xác nhận rằng điều này là/không đúng?

+0

Bạn có nhận được thông báo lỗi khi thử mở tệp docx được tạo trong Word 2010 không? – Hans

+0

Tôi có. Tôi nhận được một "Tập tin [tên tệp] không thể mở được vì có vấn đề với nội dung." Tôi nhìn vào các nội dung trong thanh tra, nhưng tôi không thấy bất cứ điều gì rõ ràng đối với những gì thực sự sai. – JasCav

Trả lời

16

Tôi có thể tạo lại lỗi "... có sự cố với nội dung" bằng cách sử dụng tài liệu HTML chưa hoàn chỉnh làm nội dung của phần nhập định dạng thay thế. Ví dụ: nếu bạn sử dụng đoạn mã HTML sau <h1>HELLO</h1> MS Word không thể mở tài liệu.

Mã bên dưới cho biết cách thêm AlternativeFormatImportPart vào tài liệu từ. (Tôi đã thử nghiệm mã với MS Word 2013).

using (WordprocessingDocument doc = WordprocessingDocument.Open(@"test.docx", true)) 
{ 
    string altChunkId = "myId"; 
    MainDocumentPart mainDocPart = doc.MainDocumentPart; 

    var run = new Run(new Text("test")); 
    var p = new Paragraph(new ParagraphProperties(
     new Justification() { Val = JustificationValues.Center }), 
        run); 

    var body = mainDocPart.Document.Body; 
    body.Append(p);   

    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("<html><head></head><body><h1>HELLO</h1></body></html>")); 

    // Uncomment the following line to create an invalid word document. 
    // MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("<h1>HELLO</h1>")); 

    // Create alternative format import part. 
    AlternativeFormatImportPart formatImportPart = 
    mainDocPart.AddAlternativeFormatImportPart(
     AlternativeFormatImportPartType.Html, altChunkId); 
    //ms.Seek(0, SeekOrigin.Begin); 

    // Feed HTML data into format import part (chunk). 
    formatImportPart.FeedData(ms); 
    AltChunk altChunk = new AltChunk(); 
    altChunk.Id = altChunkId; 

    mainDocPart.Document.Body.Append(altChunk); 
} 

Theo đặc điểm kỹ thuật Văn phòng OpenXML yếu tố cha mẹ có giá trị cho các phần tử w:altChunkbody, comment, docPartBody, endnote, footnote, ftr, hdr and tc. Vì vậy, tôi đã thêm w:altChunk vào phần tử nội dung.

Để biết thêm thông tin về thành phần w:altChunk, hãy xem liên kết MSDN này.

EDIT

Như đã chỉ ra bởi @ user2945722, để đảm bảo rằng các thư viện OpenXML correctlty giải thích mảng byte như UTF-8, bạn nên thêm lời mở đầu UTF-8. Điều này có thể được thực hiện theo cách này:

MemoryStream ms = new MemoryStream(new UTF8Encoding(true).GetPreamble().Concat(Encoding.UTF8.GetBytes(htmlEncodedString)).ToArray() 

này sẽ ngăn chặn của é của bạn không bị trả lại như, của à © 's ä của bạn như ä, vv

+0

"... sử dụng tài liệu HTML chưa hoàn chỉnh ..." - Đó chính xác là vấn đề. Một điều đơn giản như vậy, nhưng rất không rõ ràng đối với tôi. Cảm ơn bạn đã giúp đỡ. – JasCav

+3

Bạn nên xem xét việc thêm UTF8 BOM vào mảng byte trước khi chuyển nó vào bộ nhớ. Điều này đã giúp kịch bản của tôi trong đó tệp docx sẽ không hiển thị một số ký tự UTF8 chính xác. Một cái gì đó như thế này - 'byte [] utf8Bom = new UTF8Encoding (true) .GetPreamble();' và sau đó thêm vào kết quả "GetBytes" – user2945722

+0

@ user2945722 Cảm ơn! Đây là câu trả lời đúng cho vấn đề của tôi. Nó nên được bao gồm trong câu trả lời. –

1

Đã cùng một vấn đề ở đây, nhưng một nguyên nhân hoàn toàn khác. Đáng thử nếu giải pháp được chấp nhận không giúp ích gì. Thử đóng tệp sau khi lưu. Trong trường hợp của tôi, nó đã xảy ra là sự khác biệt giữa một tập tin docx bị hỏng và sạch. Thật kỳ lạ, hầu hết các hoạt động khác chỉ hoạt động với một lệnh Save() và thoát chương trình.

String cid = "chunkid"; 
WordprocessingDocument document = WordprocessingDocument.Open("somefile.docx", true); 
Body body = document.MainDocumentPart.Document.Body; 
MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("<html><head></head><body>hi</body></html>")); 
AlternativeFormatImportPart formatImportPart = document.MainDocumentPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html, cid); 
formatImportPart.FeedData(ms); 
AltChunk altChunk = new AltChunk(); 
altChunk.Id = cid; 
document.MainDocumentPart.Document.Body.Append(altChunk); 
document.MainDocumentPart.Document.Save(); 
// here's the magic! 
document.Close(); 
+0

Tôi đã cố gắng ghi vào MemoryStream (sử dụng WordprocessingDocument.Create thay vì WordprocessingDocument.Open) và "ma thuật" của document.Close() chính xác là những gì tôi cần để lấy luồng bộ nhớ sạch để trả về * NẾU * Tôi đã cố gắng trở về từ bên trong câu lệnh using (hoặc không sử dụng câu lệnh using). Quay trở lại bên ngoài câu lệnh sử dụng không yêu cầu phép thuật này. Tôi nghi ngờ rằng việc sử dụng tuyên bố có hiệu quả làm nhiệm vụ tương tự như document.Close() khi xử lý các đối tượng. –