Microsoft Office Wordで約600のレポートを作成しようとしています。ドキュメントには、データベースのデータと、ローカルドライブにある画像が読み込まれます。 Visual Studio 2010でWordテンプレートプロジェクトを作成し、テンプレートをプログラムして、単一の値(ID番号)を入力すると、ドキュメント全体が自動的に入力されるようになることがわかりました。
これが可能であると確信しています。唯一の問題です。データベース内のすべてのエントリをループし、テンプレートに基づいて新しいドキュメントを開いて、id値を設定するにはどうすればよいですか?
for(int i = 0; i < idnumbers.Count(); i++)
{
Word.Application app = new Word.Application();
Word.Document doc = app.Documents.Add(@"C:\..\WordGenerator\bin\Debug\WordTemplate.dotx");
//input the id-number below: HOW??
doc.SaveAs(FileName: @"c:\temp\test.docx");
}
アプリケーションは1回だけ実行してレポートを生成することになっているため、高速である必要はありません。開発が簡単でなければなりません。
ここでの問題は、DocumentBaseオブジェクトがWordプロジェクトの外部からアクセスできないように見えることです。代わりのMicrosoft.Office.Interop.Word.Documentには、ContentContentsを見つけて設定できるSelectContentControlsByTitleのような機能がありません。それがまさに私がしなければならないことです。
これが私のコードが次のようになり、テキストをフィールドに挿入します。Word.Application app = new Word.Application();
Word.Document doc = app.Documents.Add(@"C:\..\test.dotx");
foreach (Word.ContentControl cc in doc.SelectContentControlsByTitle("MyCCTitle"))
{
cc.Range.Text += "1234";
}
doc.SaveAs(FileName: @"c:\temp\test.docx");
次に、BeforeSaveのテンプレートのイベントハンドラーが、MyCCTitleというタイトルのオブジェクトのテキストに基づいてドキュメントに入力します。
たぶん、あなたはMicrosoft.Office.Tools.Word.Documentを見る必要がありますか?
Officeオートメーションを使用しないでください。 Officeオートメーションは、バックグラウンドでオフィスのインスタンスを開き、それにアクションを実行します。 Officeインスタンスを600回開くことは、それほど興味深いことではないようです。 (そしてサーバーサイドで実行されることは決してありません)
Open XMLを見てください。あなたはそれについての負荷を以下に見つけることができます:
編集:Openxmldeveloperをシャットダウンしています。代わりに、上記のすべてのソースを http://www.ericwhite.com/ で見つけてください。
Word 2007または2010形式を使用している場合は、OpenXML形式について読む必要があります
http://msdn.Microsoft.com/en-us/library/bb264572(office.12).aspx
ここに2つの質問があるようです:
特定のID値のプロセスをどのように開始しますか
どのようにドキュメントにデータを入力しますか。
sunilpはQ2に回答しました。データバインドコンテンツコントロールは、Word 2007以降のデータを挿入するための最良の方法です。
OPの焦点は第1四半期です。
Wordに任意の値を渡すことができるコマンドラインスイッチはありません。 http://support.Microsoft.com/kb/210565
だから私がそれを見ると、あなたには4つの選択肢があります:
openXML SDKを介してすべての作業を行い、Wordをまったく開かない(他のポスターが示唆しているように)
openXML SDkを使用して最小限の既存のドキュメント(ID番号を含む)を作成し、Wordを開く
wordを自動化して、ID番号をおそらくドキュメントのプロパティとしてドキュメントに渡す
vSTOまたはWordマクロ(VBA)を使用してWordで600ドキュメントを作成する作業を行う
私? Wordでデータバインドされたコンテンツコントロールを含むdocxを作成して保存します。
次に、私のデータをカスタムxmlパーツとしてデータに挿入し、保存します。 (この手順は、OpenXML SDKを使用して行うことができます。Wordで自分の下流プロセスのバインディングを更新する必要がある場合はWordで実行できます)
上記の回答に関して、私はOpenXMLが進むべき道であるJ. Vermeireに同意します。 OpenXMLベースのツールキットを3年以上使用しており、テンプレートとデータベースデータからマージされた.docxドキュメントを生成しています。使い方の例 here があります。この例は、一度に1つのドキュメントを処理する方法、複数のドキュメントを処理する方法を示しています。ループを追加して、ドキュメント生成用のメソッドを呼び出すだけです。
Document.OpenXml.dll
およびWindowsBase.dll
の参照を追加します
using System.IO.Packaging;
using DocumentFormat.OpenXml.Packaging;
using System.DirectoryServices;
protected void btnOK_Click(object sender, EventArgs e)
{
try
{
Package package;
string strTemplateName = ddl_Templates.SelectedValue.ToString(); //Select Dotx template
string strClaimNo = "3284112";
string strDatePart = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + DateTime.Now.Millisecond.ToString();
//Word template file
string templateName = Server.MapPath("~\\LetterTemplates\\" + strTemplateName + ".dotx");
PackagePart documentPart = null;
//New file name to be generated from
string docFileName = Server.MapPath("~\\LetterTemplates\\" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx");
File.Copy(templateName,docFileName, true);
string fileName = docFileName;
package = Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite);
DataSet DS = GetDataSet(strClaimNo, ""); // to get the data from backend to fill in for merge fields
try
{
if (DS != null)
{
if (DS.Tables.Count > 0)
{
if (DS.Tables[0].Rows.Count > 0)
{
foreach (System.IO.Packaging.PackageRelationship documentRelationship
in package.GetRelationshipsByType(documentRelationshipType))
{
NameTable nt = new NameTable();
nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w",
"http://schemas.openxmlformats.org/wordprocessingml/2006/main");
Uri documentUri = PackUriHelper.ResolvePartUri(
new Uri("/", UriKind.Relative), documentRelationship.TargetUri);
documentPart = package.GetPart(documentUri);
//Get document xml
XmlDocument xdoc = new XmlDocument();
xdoc.Load(documentPart.GetStream(FileMode.Open, FileAccess.Read));
int intMergeFirldCount = xdoc.SelectNodes("//w:t", nsManager).Count;
XmlNodeList nodeList = xdoc.SelectNodes("//w:t", nsManager);
foreach (XmlNode node in nodeList)
{
try
{
xdoc.InnerXml = xdoc.InnerXml.Replace(node.InnerText, DS.Tables[0].Rows[0][node.InnerText.Replace("«", "").Replace("»", "").Trim()].ToString());
}catch(Exception x) { }
}
StreamWriter streamPart = new StreamWriter(documentPart.GetStream(FileMode.Open, FileAccess.Write));
xdoc.Save(streamPart);
streamPart.Close();
package.Flush();
package.Close();
}
using (WordprocessingDocument template = WordprocessingDocument.Open(docFileName, true))
{
template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
template.MainDocumentPart.Document.Save();
}
byte[] bytes = System.IO.File.ReadAllBytes(docFileName);
System.IO.File.Delete(docFileName);
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "application/vnd.msword.document.12"; //"application/msword";
Response.ContentEncoding = System.Text.Encoding.UTF8;
response.AddHeader("Content-Disposition", "attachment; filename=" + strClaimNo + "_" + strTemplateName + "_" + strDatePart + ".docx;");
response.BinaryWrite(bytes);
response.Flush();
response.Close();
}
else
{
throw (new Exception("No Records Found."));
}
}
else
{
throw (new Exception("No Records Found."));
}
}
else
{
throw (new Exception("No Records Found."));
}
}
catch (Exception ex)
{
package.Flush();
package.Close();
// Softronic to add code for exception handling
}
}
catch (Exception ex)
{
// add code for exception handling
}
finally
{
}
}