2013-08-06 8 views
16

Ich versuche, die Microsoft OpenXML 2.5-Bibliothek zu verwenden, um ein OpenXML-Dokument zu erstellen. Alles funktioniert gut, bis ich versuche, eine HTML-Zeichenfolge in mein Dokument einzufügen. Ich habe das Web durchsucht und hier ist das, was ich mit so weit gekommen sind (snipped nur den Abschnitt Ich habe Probleme mit):HTML-String zu OpenXML (* .docx) hinzufügen Dokument

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); 

Offensichtlich habe ich nicht wirklich die altChunk in diesem Beispiel hinzugefügt, aber ich habe versucht, es überall anzuhängen - zum Lauf, Absatz, Körper, usw. In jedem Fall kann ich die docx-Datei in Word 2010 nicht öffnen.

Das macht mich ein wenig nussig, weil es so aussieht es sollte einfach sein (ich gebe zu, dass ich das "Ding" von AltChunk nicht vollständig verstehe). Würde mich über jede Hilfe freuen.

Side Note: Eine Sache, die ich gefunden habe, war interessant, und ich weiß nicht, ob es ein Problem ist oder nicht, ist this response, die besagt, AltChunk verdirbt die Datei beim Arbeiten von einem MemoryStream. Kann jemand bestätigen, dass das stimmt/nicht?

+0

Erhalten Sie eine Fehlermeldung, wenn Sie versuchen, die generierte docx-Datei in Word 2010 zu öffnen? – Hans

+0

tue ich. Ich bekomme ein "Die Datei [Dateiname] kann nicht geöffnet werden, da es Probleme mit dem Inhalt gibt." Ich schaue auf den Inhalt des Inspektors, aber ich sehe nichts Offensichtliches in Bezug darauf, was eigentlich falsch ist. – JasCav

Antwort

16

Ich kann den Fehler reproduzieren „... gibt es ein Problem mit dem Inhalt“ durch ein unvollständiges HTML-Dokument als Inhalt des alternativen Format importiert Teils verwendet wird. Wenn Sie beispielsweise das folgende HTML-Snippet verwenden <h1>HELLO</h1> MS Word kann das Dokument nicht öffnen.

Der folgende Code zeigt, wie Sie einem Word-Dokument eine AlternativeFormatImportPart hinzufügen. (Ich habe den Code mit MS Word 2013 getestet).

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); 
} 

gemäß der Spezifikation OpenXML gültigen übergeordneten Elemente für die w:altChunk Elemente sind body, comment, docPartBody, endnote, footnote, ftr, hdr and tc. Also, ich habe die zum Körperelement hinzugefügt.

Für weitere Informationen über das w:altChunk Element siehe MSDN Link.

EDIT

Wie von @ user2945722, um sicherzustellen, dass die OpenXml Bibliothek correctlty das Byte-Array als UTF-8 interpretiert, sollten Sie die UTF-8 Präambel hinzuzufügen. Dies kann auf diese Weise geschehen:

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

Dies wird verhindern, dass Ihre E ist als à © 's gemacht zu werden, Ihre ä die als å¤ des usw.

+0

"... mit einem unvollständigen HTML-Dokument ..." - Genau das war das Problem. So eine einfache Sache, aber für mich nicht sehr offensichtlich. Danke für Ihre Hilfe. – JasCav

+3

Sie sollten überlegen, die UTF8-Stückliste dem Bytearray hinzuzufügen, bevor Sie sie an den Speicherstream übergeben. Dies half meinem Szenario, wo die docx-Datei einige UTF8-Zeichen nicht korrekt anzeigen würde. Etwas wie das - "byte [] utf8Bom = new UTF8Encoding (true) .GetPreamble();' und dann das dem Ergebnis "GetBytes" voranstellen – user2945722

+0

@ user2945722 Danke! Das war die richtige Antwort für mein Problem. Es sollte in der Antwort enthalten sein. –

1

das gleiche Problem hier war, aber ein ganz andere Ursache. Einen Versuch wert, wenn die akzeptierte Lösung nicht hilft. Versuchen Sie, die Datei nach dem Speichern zu schließen. In meinem Fall war es der Unterschied zwischen einer korrupten und einer sauberen docx-Datei. Seltsamerweise arbeiten die meisten anderen Operationen nur mit einem Save() und einem Programm-Exit.

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

Ich habe versucht, in einen MemoryStream zu schreiben (mit WordprocessingDocument.Create anstelle von WordprocessingDocument.Open) und die "Magie" von document.Close() war genau das, was ich brauchte, um einen sauberen Speicherstream zu erhalten, wenn ich es versuchte Rückgabe innerhalb der using-Anweisung (oder keine using-Anweisung). Die Rückkehr außerhalb der using-Anweisung erforderte diese Magie nicht. Ich vermute, dass die using-Anweisung die gleiche Aufgabe erledigt wie document.Close(), wenn das Objekt entsorgt wird. –