代码之家  ›  专栏  ›  技术社区  ›  J.W.

在ASP.NET中填充Word文档?

  •  6
  • J.W.  · 技术社区  · 16 年前

    我正在处理ASP.NET项目,该项目需要填写一个Word文档。我的客户提供了一个带有姓氏、名字、出生日期等的单词模板….我在SQL数据库中拥有所有这些信息,客户希望应用程序的用户能够从数据库下载包含填充信息的Word文档。

    最好的归档方法是什么?基本上,我需要在Word文档中识别那些“可填充点”,当应用程序用户单击下载按钮时,填充这些信息。

    8 回复  |  直到 13 年前
        1
  •  6
  •   Mark    16 年前

    我不确定ASP.NET的某些方面,但我正在做一些类似的工作,您可能希望改用RTF。您可以在RTF中使用模式替换。例如,您可以在RTF文档中添加用户名这样的标记。当用户单击下载按钮时,您的应用程序可以从数据库中获取信息,并用数据库中的数据替换user_first name_的每个实例。我目前正在用PHP做这个,它工作得很好。Word将打开RTF而不会出现问题,因此这是我选择此方法的另一个原因。

        2
  •  8
  •   aquinas    16 年前

    如果可以使用Office2007,则可以使用开放式XML API来格式化文档: http://support.microsoft.com/kb/257757 . 您必须走这条路的原因是您不能在服务器环境中真正使用Word自动化。(你可以,但要想正常工作是一种巨大的痛苦,而且很容易就会崩溃)。

    如果你不能走2007年的路线,我实际上已经非常成功地打开了一个作为流的Word模板,找到并替换了令牌并将其提供给用户。在我的经验中,这实际上非常有效,而且实现起来非常简单。

        3
  •  2
  •   Rex M    16 年前

    我已经用过 Aspose.Words for .NET .虽然价格有点贵,但它工作得非常好,而且API对于一些可能非常复杂的东西是相当直观的。

    如果你想预先设计你的文件(或者允许别人为你做),任何人都可以 fields 在文档中。Aspose可以打开文档,查找和填充字段,并保存一份新的填写副本供下载。

        4
  •  2
  •   Joel Coehoorn    16 年前

    Aspose很好用,但还是很贵。

    一定要尽量避免在Web应用程序中使用Office自动化。它只是不能很好地伸缩。

    我对这类问题的首选解决方案是XML:这里我特别推荐 WordProcessingML . 根据架构创建XML文档,将 .doc 它的扩展名,MS Word将打开它,就像它是任何版本的本机版本一样,可以追溯到OfficeXP。这支持大多数Word功能,这样就可以安全地减少在文本流中替换标记的问题。

    请小心地在谷歌上搜索更多关于这方面的信息:这和Office2007的基于XML的新格式之间有很多混淆。他们不是一回事。

        5
  •  1
  •   Lee Richardson    16 年前

    此代码适用于WordML文本框和复选框。它是基于索引的,所以只需为所有文本框传递一个字符串数组,为所有复选框传递一个bool数组。

    public void FillInFields(
        Stream sourceStream,
        Stream destinationStream,
        bool[] pageCheckboxFields,
        string[] pageTextFields
        ) {
    
        StreamUtil.Copy(sourceStream, destinationStream);
        sourceStream.Close();
    
        destinationStream.Seek(0, SeekOrigin.Begin);
    
        Package package = Package.Open(destinationStream, FileMode.Open, FileAccess.ReadWrite);
        Uri uri = new Uri("/word/document.xml", UriKind.Relative);
    
        PackagePart packagePart = package.GetPart(uri);
        Stream documentPart = packagePart.GetStream(FileMode.Open, FileAccess.ReadWrite);
        XmlReader xmlReader = XmlReader.Create(documentPart);
    
        XDocument xdocument = XDocument.Load(xmlReader);
    
        List<XElement> textBookmarksList = xdocument
            .Descendants(w + "fldChar")
            .Where(e => (e.AttributeOrDefault(w + "fldCharType") ?? "") == "separate")
            .ToList();
    
        var textBookmarks = textBookmarksList.Select(e => new WordMlTextField(w, e, textBookmarksList.IndexOf(e)));
    
        List<XElement> checkboxBookmarksList = xdocument
            .Descendants(w + "checkBox")
            .ToList();
    
        IEnumerable<WordMlCheckboxField> checkboxBookmarks = checkboxBookmarksList
            .Select(e => new WordMlCheckboxField(w, e, checkboxBookmarksList.IndexOf(e)));
    
        for (int i = 0; i < pageTextFields.Length; i++) {
            string value = pageTextFields[i];
            if (!String.IsNullOrEmpty(value))
                SetWordMlElement(textBookmarks, i, value);
        }
    
        for (int i = 0; i < pageCheckboxFields.Length; i++) {
            bool value = pageCheckboxFields[i];
            SetWordMlElement(checkboxBookmarks, i, value);
        }
    
        PackagePart newPart = packagePart;
        StreamWriter streamWriter = new StreamWriter(newPart.GetStream(FileMode.Create, FileAccess.Write));
        XmlWriter xmlWriter = XmlWriter.Create(streamWriter);
        if (xmlWriter == null) throw new Exception("Could not open an XmlWriter to 4311Blank-1.docx.");
        xdocument.Save(xmlWriter);
    
        xmlWriter.Close();
        streamWriter.Close();
        package.Flush();
    
        destinationStream.Seek(0, SeekOrigin.Begin);
    }
    
    private class WordMlTextField {
        public int? Index { get; set; }
        public XElement TextElement { get; set; }
    
        public WordMlTextField(XNamespace ns, XObject element, int index) {
            Index = index;
    
            XElement parent = element.Parent;
            if (parent == null) throw new NicException("fldChar must have a parent.");
            if (parent.Name != ns + "r") {
                log.Warn("Expected parent of fldChar to be a run for fldChar at position '" + Index + "'");
                return;
            }
            var nextSibling = parent.ElementsAfterSelf().First();
    
            if (nextSibling.Name != ns + "r") {
                log.Warn("Expected a 'r' element after the parent of fldChar at position = " + Index);
                return;
            }
    
            var text = nextSibling.Element(ns + "t");
            if (text == null) {
                log.Warn("Expected a 't' element inside the 'r' element after the parent of fldChar at position = " + Index);
            }
    
            TextElement = text;
        }
    }
    
    private class WordMlCheckboxField {
        public int? Index { get; set; }
        public XElement CheckedElement { get; set; }
        public readonly XNamespace _ns;
    
        public WordMlCheckboxField(XNamespace ns, XContainer checkBoxElement, int index) {
            _ns = ns;
            Index = index;
    
            XElement checkedElement = checkBoxElement.Elements(ns + "checked").FirstOrDefault();
            if (checkedElement == null) {
                checkedElement = new XElement(ns + "checked", new XAttribute(ns + "val", "0"));
                checkBoxElement.Add(checkedElement);
            }
    
            CheckedElement = checkedElement;
        }
    
        public static void Copy(Stream readStream, Stream writeStream) {
            const int Length = 256;
            Byte[] buffer = new Byte[Length];
            int bytesRead = readStream.Read(buffer, 0, Length);
            // write the required bytes
            while (bytesRead > 0) {
                writeStream.Write(buffer, 0, bytesRead);
                bytesRead = readStream.Read(buffer, 0, Length);
            }
            readStream.Flush();
            writeStream.Flush();
        }
    
        6
  •  0
  •   Community CDub    7 年前

    一般来说,您希望避免在服务器上执行Office自动化,而Microsoft甚至 stated that it is a bad idea as well . 然而,我通常使用的技术是 Office Open XML 注意到的是 aquinas . 学习这种格式的方法确实需要一点时间,但是一旦你这样做了,就很值得了,因为你不必担心与办公自动化相关的一些问题(例如流程挂起)。

    不久前,我回答了一个类似的问题,你可能会发现它是有用的,你可以找到它。 here .

        7
  •  0
  •   Eisbaer    13 年前

    如果您需要在文档文件(而不是docx)中这样做,那么OpenXML SDK将不会帮助您。

    另外,只想添加另一个+1,说明在服务器上自动运行Office应用程序的危险。你会遇到规模的问题-我保证。

    要添加对可用于解决问题的第三方工具的另一个引用,请执行以下操作:

    http://www.officewriter.com

    OfficeWriter允许您使用完整的API或基于模板的方法(如您的需求)控制文档,该方法基本上允许您在这样的场景中打开、绑定和保存文档和docx,只需很少的代码。

        8
  •  -3
  •   Dean    16 年前

    您不能使用Microsoft自己的互操作框架来使用Word功能吗?

    Here