2009-07-17 37 views
6

Tôi đang sử dụng Word và OpenXML để cung cấp chức năng mail merge trong một ứng dụng web C# ASP.NET:tài liệu Nhân bản Lời sử dụng OpenXML và C#

1) Một tài liệu được tải lên với một số chuỗi được xác định trước sử dụng quyền thay .

2) Sử dụng OpenXML SDK 2.0 Tôi mở tài liệu Word, lấy mainDocumentPart dưới dạng chuỗi và thực hiện thay thế bằng Regex.

3) Sau đó tôi tạo một tài liệu mới bằng cách sử dụng OpenXML, thêm một mainDocumentPart mới và chèn chuỗi kết quả từ việc thay thế vào mainDocumentPart này.

Tuy nhiên, tất cả định dạng/kiểu, v.v. đều bị mất trong tài liệu mới.

Tôi đoán tôi có thể sao chép và thêm Kiểu, Định nghĩa, Phần nhận xét, v.v. riêng để bắt chước tài liệu gốc.

Tuy nhiên, có phương pháp nào sử dụng Open XML để sao chép tài liệu cho phép tôi thực hiện các thay thế trên bản sao mới không?

Cảm ơn.

Trả lời

-1

Khi bạn xem tài liệu openxml bằng cách thay đổi phần mở rộng thành zip và mở nó, bạn sẽ thấy thư mục con đó chứa thư mục _rels nơi tất cả các mối quan hệ được liệt kê. Các mối quan hệ này trỏ đến các phần bạn đã đề cập (kiểu ...). Thực ra bạn cần những phần này vì chúng chứa định nghĩa của định dạng. Vì vậy, không sao chép chúng sẽ khiến tài liệu mới sử dụng định dạng được xác định trong tệp normal.dot chứ không phải định dạng được xác định trong tài liệu gốc. Vì vậy, tôi nghĩ bạn phải sao chép chúng.

+0

không thực sự trả lời câu hỏi. đọc về cách làm điều đó trước khi trả lời. –

2

Tôi đã thực hiện một số điều rất giống nhau, nhưng thay vì sử dụng chuỗi thay thế văn bản, tôi sử dụng Điều khiển nội dung từ. Tôi đã ghi lại một số chi tiết trong bài đăng trên blog sau, SharePoint and Open Xml. Kỹ thuật này là không phải là dành riêng cho SharePoint. Bạn có thể tái sử dụng mẫu trong ASP.NET thuần túy hoặc các ứng dụng khác.

Ngoài ra, tôi chắc chắn sẽ khuyến khích bạn xem lại Eric White's Blog để biết các mẹo, thủ thuật và kỹ thuật về Open Xml. Cụ thể, hãy xem in-memory manipulation of Open Xml postWord content controls bài đăng. Tôi nghĩ rằng bạn sẽ tìm thấy những hữu ích hơn nhiều trong thời gian dài.

Hy vọng điều này sẽ hữu ích.

4

Tôi thứ hai sử dụng đề xuất Kiểm soát nội dung. Sử dụng chúng để đánh dấu các khu vực của tài liệu của bạn, nơi bạn muốn thực hiện thay thế là bằng cách dễ nhất để làm điều đó.

Đối với sao chép tài liệu (và giữ lại các nội dung tài liệu toàn bộ, phong cách và tất cả) nó tương đối dễ dàng:

string documentURL = "full URL to your document"; 
byte[] docAsArray = File.ReadAllBytes(documentURL); 

using (MemoryStream stream = new MemoryStream) 
{ 
    stream.Write(docAsArray, 0, docAsArray.Length); // THIS performs doc copy 
    using (WordprocessingDocument doc = WordprocessingDocument.Open(stream, true)) 
    { 
     // perform content control substitution here, making sure to call .Save() 
     // on any documents Part's changed. 
    } 
    File.WriteAllBytes("full URL of your new doc to save, including .docx", stream.ToArray()); 
} 

Trên thực tế việc tìm kiếm các điều khiển nội dung là một miếng bánh sử dụng LINQ. Ví dụ sau đây tìm tất cả các điều khiển đơn giản nội dung văn bản (được đánh máy như SdtRun):

using (WordprocessingDocument doc = WordprocessingDocument.Open(stream, true)) 
{      
    var mainDocument = doc.MainDocumentPart.Document; 
    var contentControls = from sdt in mainDocument.Descendants<SdtRun>() select sdt; 

    foreach (var cc in contentControls) 
    { 
     // drill down through the containment hierarchy to get to 
     // the contained <Text> object 
     cc.SdtContentRun.GetFirstChild<Run>().GetFirstChild<Text>().Text = "my replacement string"; 
    } 
} 

các <Run><Text> yếu tố có thể chưa tồn tại nhưng việc tạo ra chúng là một đơn giản như:

cc.SdtContentRun.Append(new Run(new Text("my replacement string"))); 

Hope giúp ai đó.: D

2

Làm phụ lục cho phần trên; những gì có lẽ hữu ích hơn là tìm kiếm các điều khiển nội dung đã được gắn thẻ (sử dụng GUI từ). Gần đây tôi đã viết một số phần mềm có các mẫu tài liệu chứa các điều khiển nội dung có gắn thẻ. Để tìm chúng chỉ là phần mở rộng của truy vấn LINQ ở trên:

var mainDocument = doc.MainDocumentPart.Document; 
var taggedContentControls = from sdt in mainDocument.Descendants<SdtElement>() 
          let sdtPr = sdt.GetFirstChild<SdtProperties>() 
          let tag = (sdtPr == null ? null : sdtPr.GetFirstChild<Tag>()) 
          where (tag != null) 
          select new 
          { 
           SdtElem = sdt, 
           TagName = tag.GetAttribute("val", W).Value 
          }; 

Tôi nhận mã này từ nơi khác nhưng không thể nhớ tại thời điểm này; tín dụng đầy đủ sẽ đến với họ.

Truy vấn chỉ tạo một IEnumerable của một loại ẩn danh có chứa điều khiển nội dung và thẻ được liên kết của nó làm thuộc tính. Tiện dụng!

10

Đoạn mã này sẽ sao chép tất cả các phần từ tài liệu hiện tại sang tài liệu mới.

using (var mainDoc = WordprocessingDocument.Open(@"c:\sourcedoc.docx", false)) 
using (var resultDoc = WordprocessingDocument.Create(@"c:\newdoc.docx", 
    WordprocessingDocumentType.Document)) 
{ 
    // copy parts from source document to new document 
    foreach (var part in mainDoc.Parts) 
    resultDoc.AddPart(part.OpenXmlPart, part.RelationshipId); 
    // perform replacements in resultDoc.MainDocumentPart 
    // ... 
} 
+1

Tôi đã đập đầu vào tường nhiều giờ đồng hồ với việc kinh doanh MemoryStream ... Điều này hoạt động tốt và ngắn gọn hơn nhiều. Cảm ơn nhiều! – lukiffer

+0

Có cách nào để làm một điều tương tự, khác biệt duy nhất là nội dung trong 'mainDoc' cần được nối vào cuối tài liệu hiện có? –

+0

Có, mặc dù khó khăn hơn nhiều, vì rất nhiều dữ liệu từ các phần của cả hai tài liệu cần phải được hợp nhất. Rất may, [Eric White] (http://ericwhite.com/blog/) đã xây dựng một bộ [PowerTools for OpenXML] (http://ericwhite.com/blog/category/open-xml/powertools/) nhiệm vụ khó khăn này cho bạn. Đặc biệt, hãy xem [DocumentBuilder] (http://openxmldeveloper.org/wiki/w/wiki/documentbuilder.aspx) mà tôi đã sử dụng để nối thêm một tài liệu với tài liệu khác trong quá khứ. Làm việc như người ở! – bernhof

Các vấn đề liên quan