2016-03-31 3 views
0

У меня есть .docx, который включает MailMerge, мне нужно изменить его источник с помощью кода (C#). В качестве библиотеки я использую OpenXml. Открыв docx как zip-файл и ищет пути, я обнаружил, что ссылка источника данных хранится в двух разных местах: в word/settings.xml и в word/_rels/settings.xml.rels.Редактировать MailMerge через OpenXml

Для замены Fisrt:

var template = new MemoryStream(myDocxInByteArray); 

using (var doc = DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(template, true)) 
{ 
    var s = doc.MainDocumentPart.DocumentSettingsPart.Settings; 
    foreach (var els in s.ChildElements) 
    { 
     if (els is DocumentFormat.OpenXml.Wordprocessing.MailMerge) 
     { 
      var mm = (DocumentFormat.OpenXml.Wordprocessing.MailMerge)els; 

      mm.Query.Val = "SELECT * FROM " + myNewPath; 

      break; 
     } 
    } 
} 

Это прекрасно работает, однако при открытии файла Слово требующего, чтобы загрузить файл с новым путем, но и от старого, так как она определена в word/_rels/settings.xml.rels ,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> 
    <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/mailMergeSource" Target="oldPath" TargetMode="External"/> 
</Relationships> 

Как я могу найти этот объект (Relation) в WordprocessingDocument? Не можете найти его ... Или есть другой способ его изменить?

EDIT:

Я создал два различные пустые файлы с другим источником, а затем открыть с помощью OpenXml Productivity Tool для того, чтобы сравнить их. Поскольку я уже видел различия в word/settings.xml и в word/_rels/settings.xml.rels.

+0

Try открытие документа в Word, изменение источника данных, а затем сохранение его с другим именем. Используйте функцию «Сравнить» в Инструменте производительности Open XML SDK, чтобы увидеть код, который он генерирует, чтобы изменить один документ на другой. FWIW, вам, вероятно, потребуется создать новый идентификатор отношения (который будет сохранен в файле rels) и использовать его для замены/удаления rId1. Обычно это работает с Open XML SDK. –

+0

Хорошо, но как мне удалить старые отношения? Я не могу найти его, открывая его с помощью OpenXml ... – Emaborsa

ответ

0

В конце концов, я придумал следующее решение:

using (WordprocessingDocument doc = WordprocessingDocument.Open(docInByteArray, isEditable: true)) 
{ 
    Settings settings = doc.MainDocumentPart.DocumentSettingsPart.Settings; 
    OpenXmlElement openXmlElement = null; 
    foreach (OpenXmlElement element in settings.ChildElements) 
    { 
     if (element is MailMerge mailMerge) 
     { 
      mailMerge.Query.Val = "SELECT * FROM " + csvPath; 
      mailMerge.DataSourceObject.Remove(); 
     } 
     else if (element is AttachedTemplate) 
     { 
      openXmlElement = element; 
     } 
    } 
    if (openXmlElement != null) 
    { 
     openXmlElement.Remove(); 
    } 
    doc.Save(); 
} 
0

Я считаю, что вы можете сделать это таким образом, если у вас уже есть соответствующий идентификатор отношения rID (идентификатор отношения) в соответствующей части XML-файла настроек. Подход, который я даю, зависит от Linq.

Но имейте в виду, что Word может хранить два Имена файлов источника данных в файле Settings.xml с двумя соответствующими отношениями в settings.xml.rels. Более того, они оба имеют одну и ту же строку типа отношения. Слово AIUI фактически не использует имя файла данных в ODSO («Объект источника данных Office») в настройках MailMerge, но вы должны проверить.

Один из способов добраться до старого отношения следующим образом (это требует Linq, как он стоит):

// Get the Settings part 
var settingsPart = wordDocument.MainDocumentPart.DocumentSettingsPart; 

// Create a MailMerge object and populate it with the existing data 
// (You do not have to do this - you could get the individual 
// elements/attributes from the part's XML) 

var mailMerge = 
    new MailMerge(settingsPart.Settings.ChildElements.First<MailMerge>().OuterXml); 

// Get the relationship 

ReferenceRelationship oldRel 
    = settingsPart.ExternalRelationships.Where(
     Rel => Rel.Id == mailMerge.DataSourceReference.Id 
    ).First(); 

/* 
// to get the ODSO relationship, use the following, and to replace it, follow the pattern I give below for oldRel and newRel 
ReferenceRelationship oldOdsoRel = 
    settingsPart.ExternalRelationships.Where(
    Rel => Rel.Id == mailMerge.DataSourceObject.SourceReference.Id 
).First(); 
*/ 

// Delete the old Relationship (but notice that the oldRel object remains) 

settingsPart.DeleteExternalRelationship(oldRel.Id); 
var newRel = 
    settingsPart.AddExternalRelationship(
    oldRel.RelationshipType, 
    new Uri("your file path/name",UriKind.RelativeOrAbsolute), 
    oldRel.Id); 
+0

Я уже пытался удалить запись из внешних связей, но 'settingsPart.ExternalRelationships' равно null. – Emaborsa

+0

Если вам разрешено, отредактируйте исходный вопрос, чтобы включить код, который вы использовали для получения и удаления отношений. Я также предлагаю вам попробовать создать (в Word) новый документ с похожим источником данных и протестировать ваш код против этого. –

Смежные вопросы