Harish
Harish

Reputation: 160

Unable to find Merge Fields in word using open xml

am having trouble in finding the merge fields using the below syntax

foreach (var field in docx.MainDocumentPart.Document.Descendants<SimpleField>())
{
}

sometimes the above code works and finds out the mergefields and sometimes it just shows null

Upvotes: 3

Views: 4278

Answers (3)

Brent
Brent

Reputation: 4876

Years later, summarising the 2 answers above, the code solution to create a lookup of all the mergefields by name:

var splitter = new[] { ' ', '"' };
const string mergefield = "MERGEFIELD";
var mergeFields = mainPart.HeaderParts.Cast<OpenXmlPart>()
    .Concat(mainPart.FooterParts.Cast<OpenXmlPart>())
    .Concat(new OpenXmlPart[] { mainPart })
    .SelectMany(x => x.RootElement.Descendants<SimpleField>().Select(sf => new { text = sf.Instruction.Value, el = (OpenXmlElement)sf })
                    .Concat(x.RootElement.Descendants<FieldCode>().Select(fc=> new { text = fc.Text, el = (OpenXmlElement)fc})))
    .Select(a => new { words = a.text.Split(splitter, StringSplitOptions.RemoveEmptyEntries), el = a.el })
    .Where(a => mergefield.Equals(a.words.FirstOrDefault(), StringComparison.OrdinalIgnoreCase))
    .ToLookup(k => string.Join(" ",k.words.Skip(1).TakeWhile(i=>i!= "\\*")), v => v.el);

Upvotes: 2

Mahmoud Abdou
Mahmoud Abdou

Reputation: 106

The issue is that word can implement the merge field as SimpleField or FieldChar. The SimpleField element contains all the details of the merge fields, as for the FieldChar it has a begin element followed by the field code, paragraph with a run and text to store the field display value and finally the merge field end element. All the elements between the begin and finish belong to the merge field.

Merge field implemented as FieldChar

<w:r>
  <w:fldChar w:fldCharType="begin" />
</w:r>
<w:r>
  <w:instrText xml:space="preserve"> MERGEFIELD  AnotherBodyField  \* MERGEFORMAT </w:instrText>
</w:r>
<w:r>
  <w:fldChar w:fldCharType="separate" />
</w:r>
<w:r w:rsidR="003A6EEC">
  <w:rPr>
    <w:noProof />
  </w:rPr>
  <w:t>«AnotherBodyField»</w:t>
</w:r>
<w:r>
  <w:rPr>
    <w:noProof />
  </w:rPr>
  <w:fldChar w:fldCharType="end" />
</w:r>

Merge field implemented as SimpleField

<w:fldSimple w:instr=" MERGEFIELD  TestMergField  \* MERGEFORMAT ">
    <w:r w:rsidR="00C44AC1">
      <w:rPr>
        <w:noProof />
      </w:rPr>
      <w:t>«TestMergField»</w:t>
    </w:r>
</w:fldSimple>

The SimpleField object contains all the merge field content, so this code would do. var simpleMergeField = documentProcessor.MainDocumentPart.Document.Body.Descendants();

For the FieldChar, you need need to watch for the FieldCharValues.Begin, FieldCharValues.Separate and FieldCharValues.End. every element in between is included in the merge field content.

Upvotes: 3

MaheshMajeti
MaheshMajeti

Reputation: 187

Please verify once whether your merge field present which part of document.Itmay present in header or footer parts.You can find out this by making xml package.check each header,footer xmls.

you can loop through header parts and footerparts using below statements

foreach (var header in docx.MainDocumentPart.Headerparts)
    {

        foreach (var field in header.RootElement.Descendants<SimpleField>())
        {
        }
    }
     foreach (var footerin docx.MainDocumentPart.FooterParts)
    {

        foreach (var field in footer.RootElement.Descendants<SimpleField>())
        {
        }
    }

Upvotes: 0

Related Questions