title: Unable to extract mailmerge fields from Word DOCX using PHP and DOM
body: <p>I'm trying to come up with a solution that will allow users to upload a mail merge-enabled Word DOCX template file.  Ideally, the system will read the DOCX file, extract the XML, find the mail merge fields and save them to a database for mapping down the road.  I may go with a SOAP service such as Zend LiveDocX or PHPDOCX or something else entirely -- but for now I need to figure out how to identify the fields in a DOCX file.  To do that I've started with this article: <a href="http://dfmaxwell.wordpress.com/2012/02/24/using-php-to-process-a-word-document-mail-merge/" rel="nofollow">http://dfmaxwell.wordpress.com/2012/02/24/using-php-to-process-a-word-document-mail-merge/</a></p>
  
  <p>I've adapted it a bit to my needs (which may be a problem, though I get the same error with the original code as well.)  Specifically I'm not using it to perform the mail merge at this time, I just want to identify the fields.  Here's what I've got:</p>
  
  <pre><code>    $newFile = '/var/www/mysite.com/public_html/template.docx';
  
      $zip = new ZipArchive();
      if( $zip-&gt;open( $newFile, ZIPARCHIVE::CHECKCONS ) !== TRUE ) { echo 'failed to open template'; exit; }
      $file = 'word/document.xml';
      $data = $zip-&gt;getFromName( $file );
      $zip-&gt;close();
  
      $doc = new DOMDocument();
      $doc-&gt;loadXML( $data );
      $wts = $doc-&gt;getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'fldChar');
  
      $mergefields = array();
  
      function getMailMerge(&amp;$wts, $index) {
          $loop = true;
          $counter = $index;
          $startfield = false;
          while ($loop) {
              if ($wts-&gt;item($counter)-&gt;attributes-&gt;item(0)-&gt;nodeName == 'w:fldCharType') {
                  $nodeName = '';
                  $nodeValue = '';
                  switch ($wts-&gt;item($counter)-&gt;attributes-&gt;item(0)-&gt;nodeValue) {
                      case 'begin':
                          if ($startfield) {
                              $counter = getMailMerge($wts, $counter);
                          }
                          $startfield = true;
                          if ($wts-&gt;item($counter)-&gt;parentNode-&gt;nextSibling) {
                              $nodeName = $wts-&gt;item($counter)-&gt;parentNode-&gt;nextSibling-&gt;childNodes-&gt;item(1)-&gt;nodeName;
                              $nodeValue = $wts-&gt;item($counter)-&gt;parentNode-&gt;nextSibling-&gt;childNodes-&gt;item(1)-&gt;nodeValue;
                          }
                          else {
                              // No sibling
                              // check next node
                              $nodeName = $wts-&gt;item($counter + 1)-&gt;parentNode-&gt;previousSibling-&gt;childNodes-&gt;item(1)-&gt;nodeName;
                              $nodeValue = $wts-&gt;item($counter + 1)-&gt;parentNode-&gt;previousSibling-&gt;childNodes-&gt;item(1)-&gt;nodeValue;
                          }
                          if (substr($nodeValue, 0, 11) == ' MERGEFIELD') {
                              $mergefields[] = strtolower(str_replace('"', '', trim(substr($nodeValue, 12))));
                          }
                          $counter++;
                      break;
                  case 'separate':
                      $counter++;
                      break;
                  case 'end':
                      if ($startfield) {
                          $startfield = false;
                      }
                      $loop = false;
                  }
              }
          }
          return $counter;
      }
  
      for ($x = 0; $x &lt; $wts-&gt;length; $x++) {
          if ($wts-&gt;item($x)-&gt;attributes-&gt;item(0)-&gt;nodeName == 'w:fldCharType' &amp;&amp; $wts-&gt;item($x)-&gt;attributes-&gt;item(0)-&gt;nodeValue == 'begin') {
              $newcount = getMailMerge($wts, $x);
              $x = $newcount;
          }
      }
  </code></pre>
  
  <p>I have no problem opening the DOCX file with ZipArchive() and if I use print_r($doc->saveHTML()); I see the XML data just fine.  The problem is that when I execute my code I get Fatal error: Call to a member function item() on a non-object pointing to this:</p>
  
  <pre><code>$nodeName = $wts-&gt;item($counter)-&gt;parentNode-&gt;nextSibling-&gt;childNodes-&gt;item(1)-&gt;nodeName;
  </code></pre>
  
  <p>Google has let me down when trying to figure out this error, can anyone point me in the right direction?  Thanks in advance!</p>