Как программно создавать текстовые документы из шаблона

Я пытаюсь создать около 600 отчетов в Microsoft Word Word. Документы заполняются данными из базы данных и изображениями, найденными на локальном диске. Я выяснил, что я мог бы создать проект Word Template в visual studio 2010 и запрограммировать шаблон, чтобы при вводе единственного значения (id-number) он автоматически заполнял весь документ.

Я вполне уверен, что это возможно. единственная проблема. Как мне пройти через все записи в базе данных, открыть новый документ на основе шаблона и установить значение 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"); 
}

Приложение должно запускаться только один раз, генерируя отчеты, и оно не должно быть быстрым. Это просто должно быть легко развиваться.

Проблема здесь в том, что кажется, что объект DocumentBase недоступен вне проекта Word. Подменю Microsoft.Office.Interop.Word.Document не имеет таких функций, как SelectContentControlsByTitle, что позволяет мне находить и устанавливать мои ContentControls. И это именно то, что мне нужно сделать.

Вот как выглядит мой код сейчас, чтобы вставить текст в мое поле:             Приложение Word.Application = новое 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.

Ответы

Ответ 2

Не используйте Office Automation. Автоматизация офиса открывает экземпляр офиса в фоновом режиме и выполняет действия над ним. Открытие офисного экземпляра 600 раз не кажется очень интересным занятием. (и он никогда не будет работать на стороне сервера)

Посмотрите на Open XML. Вы можете найти множество об этом ниже:

http://openxmldeveloper.org/

редактировать: Openxmldeveloper закрывается. Вместо этого найдите все источники, упомянутые выше, на http://www.ericwhite.com/.

Ответ 4

Кажется, здесь есть два вопроса:

  • Как вы начинаете процесс для определенного значения id

  • Как вы заполняете документ.

sunilp ответил на Q2. Элементы управления содержимым с привязкой к данным - лучший способ для ввода данных для Word 2007 и более поздних версий.

Фокус OP выглядит Q1.

Нет переключателя командной строки, который позволяет передавать произвольное значение в Word: http://support.microsoft.com/kb/210565

Итак, я вижу, у вас есть 4 варианта:

  • выполните всю работу через SDK OpenXML, никогда не открывая Word вообще (как предполагали другие плакаты)

  • создайте минимальный предварительно существующий документ (содержащий номер вашего идентификатора), используя OpenXML SDK, затем откройте Word

  • автоматизировать Word, чтобы передать номер документа в документ, возможно, как свойство документа

  • выполните работу по созданию 600 документов в Word с использованием макросов VSTO или Word (VBA)

Me? Я бы создал docx, содержащий связанные с данными элементы управления содержимым в Word, и сохранил его.

Затем, введя мои данные в него как пользовательскую часть xml и сохраните ее. (Этот шаг можно сделать с помощью OpenXML SDK или Word, если вам нужно, чтобы Word обновлял привязки для вашего последующего процесса)

Ответ 5

В отношении ответов выше я согласен с J. Vermeire, что OpenXML - это путь. Я уже более трех лет использую инструментарий на базе OpenXML, который создает документы .docx, объединенные с шаблонами и данными базы данных. Ниже приведен пример использования здесь. В этом примере показано, как работать с одним документом в то время, работать с большим количеством из них, просто добавить цикл и вызвать метод для генерации документа.

Ответ 6

Добавьте ссылки для 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
        {

        }
    }

Ответ 7

foreach (System.IO.Packaging.PackageRelationship documentRelationship in package.GetRelationshipsByType(documentRelationshipType))

каким должен быть documentRelationshipType? это не определено. можете ли вы дать мне знать, что объявить...