web-dev-qa-db-ja.com

OpenXML(* .docx)ドキュメントにHTML文字列を追加する

MicrosoftのOpenXML 2.5ライブラリを使用してOpenXMLドキュメントを作成しようとしています。ドキュメントにHTML文字列を挿入しようとするまで、すべてがうまくいきます。私はウェブを精査しました、そしてこれは私がこれまでに思いついたものです(私が問題を抱えている部分だけに切り詰められます):

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

明らかに、この例では実際にaltChunkを追加していませんが、ラン、段落、本文など、どこにでも追加しようとしました。Word2010でdocxファイルを開くことができません。

単純明快なように見えるので、これは少し気が抜けています(AltChunkの「もの」を完全に理解していないことは認めます)。どんな助けにも感謝します。

補足:興味深いことに、実際に問題であるかどうかはわかりませんが、 この応答 は、MemoryStreamから作業しているときにAltChunkがファイルを破損することを示しています。誰かがこれが正しいかどうかを確認できますか?

21
JasCav

エラーを再現できます "...内容に問題があります"不完全なHTMLドキュメントを代替形式のインポート部分のコンテンツとして使用することで。たとえば、次のHTMLスニペット<h1>HELLO</h1>を使用すると、MS Wordはドキュメントを開くことができません。

以下のコードは、AlternativeFormatImportPartをWord文書に追加する方法を示しています。 (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);
}

Office OpenXML仕様によると、w:altChunk要素の有効な親要素はbody, comment, docPartBody, endnote, footnote, ftr, hdr and tcです。そこで、w:altChunkをbody要素に追加しました。

w:altChunk要素の詳細については、この [〜#〜] msdn [〜#〜] リンクを参照してください。

[〜#〜]編集[〜#〜]

@ user2945722で指摘されているように、OpenXmlライブラリがバイト配列をUTF-8として正しく解釈できるようにするには、UTF-8プリアンブルを追加する必要があります。これは次の方法で行うことができます:

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

これにより、éがéとして、äがäとしてレンダリングされるのを防ぐことができます。

22
Hans

ここでは同じ問題がありましたが、原因はまったく異なります。受け入れられた解決策が役に立たないなら、試してみる価値があります。保存後にファイルを閉じてみてください。私の場合、それはたまたま破損したdocxファイルとクリーンなdocxファイルの違いでした。奇妙なことに、他のほとんどの操作はSave()とプログラムの終了のみで機能します。

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();
2
pragmar