我正在研究需要填写word文档的Asp.Net项目。我的客户提供了一个包含姓氏,名字,出生日期等的单词模板。我在sql数据库中拥有所有这些信息,客户希望应用程序的用户能够从数据库中下载带有填写信息的word文档。
归档此内容的最佳方式是什么?基本上,我需要在word文档中识别那些“可填充点”,在应用程序用户点击下载按钮时填写这些信息。
答案 0 :(得分:8)
如果您可以使用Office 2007,那么可以使用Open XML API来格式化文档: http://support.microsoft.com/kb/257757。您必须走这条路的原因是您无法在服务器环境中真正使用Word Automation。 (你可以,但要正常工作是一件巨大的痛苦,并且可以轻松破解)。
如果你不能走2007年的路线,我实际上已经取得了相当不错的成功,只需打开一个单词模板作为流,找到并替换令牌并将其提供给用户。实际上,这实际上在我的经验中表现得非常好,实现起来非常简单。
答案 1 :(得分:6)
我不确定某些ASP.Net方面,但我正在研究类似的东西,你可能想要研究使用RTF。您可以在RTF中使用模式替换。例如,您可以在RTF文档中添加{USER_FIRST_NAME}等标记。当用户单击下载按钮时,您的应用程序可以从数据库中获取信息,并将{USER_FIRST_NAME}的每个实例替换为数据库中的数据。我目前正在使用PHP进行此操作,效果很好。 Word会毫无问题地打开RTF,这是我选择此方法的另一个原因。
答案 2 :(得分:2)
我使用了 Aspose.Words for .NET 。这是有点昂贵的一面,但它的工作非常好,API非常直观,可能非常复杂。
如果您想预先设计文档(或允许其他人为您执行此操作),任何人都可以将fields放入文档中。 Aspose可以打开文档,查找并填写字段,并保存新的已填写的副本以供下载。
答案 3 :(得分:2)
Aspose工作正常,但又一次:价格昂贵。
尽可能避免在网络应用中使用Office Automation。它只是不能很好地扩展。
我对此类问题的首选解决方案是xml:具体来说我推荐WordProcessingML。您可以根据架构创建一个Xml文档,在其上放置一个.doc
扩展名,MS Word将打开它,就像它在Office XP中的任何版本中都是本机的一样。这支持大多数Word功能,这样您就可以安全地减少在文本流中替换令牌的问题。
请仔细搜索有关此内容的更多信息:Office 2007与基于Xml的新格式之间存在很多混淆。它们不是一回事。
答案 4 :(得分:1)
此代码适用于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();
}
答案 5 :(得分:0)
通常,您将要避免在服务器上执行Office自动化,而Microsoft甚至要stated that it is a bad idea as well。但是,我通常使用的技术是Office Open XML注意到的aquinas。学习这种格式确实需要花费一些时间,但是一旦你做到这一点就非常值得,因为你不必担心Office自动化涉及的一些问题(例如进程挂起)。
前一段时间我回答了一个类似的问题,你可能会发现它很有用,你可以找到here。
答案 6 :(得分:0)
如果您需要在DOC文件(而不是DOCX)中执行此操作,那么OpenXML SDK将无法帮助您。
此外,只想添加另外+1关于在服务器上自动化Office应用程序的危险。你会遇到规模问题 - 我保证。
添加对可用于解决问题的第三方工具的其他引用:
OfficeWriter允许您使用完整的API或基于模板的方法(就像您的要求一样)控制文档,它基本上允许您在使用少量代码的情况下打开,绑定和保存DOC和DOCX。
答案 7 :(得分:-3)
你能不能使用微软自己的InterOp Framework来利用Word功能
请参阅Here