Opposite of xml_parse_into_struct?



我正试图编写一系列函数,这些函数将提取MS Word DOCX文件的document.xml部分,并有效地邮件合并一系列键/值对,以替换文档中定义的模板字段。我有一个函数使用xml_parse_into_struct将XML文本转换为必要的数组,但是一旦我完成了替换文本,我将(大概)需要使用ZipArchive方法addFromString来创建新的document.xml文件并将其添加到DOCX zip容器中。但是,当我使用数据数组而不是XML字符串时,我不确定如何做到这一点。是否有一种方法将数组转换回XML字符串格式?

到目前为止我写的是:

// $filename = name of DOCX file to open
function get_docx_xml($filename) {
  // Extract XML from DOCX file
    $zip = new ZipArchive();
    if ($zip->open($filename, ZIPARCHIVE::CHECKCONS) !== TRUE) { echo 'failed to open template'; exit; }
    $xml = 'word/document.xml';
    $data = $zip->getFromName($xml);
    $zip->close();
    // Create the XML parser and create an array of the results
    $parser = xml_parser_create_ns();
    xml_parse_into_struct($parser, $data, $vals, $index);
    xml_parser_free($parser);
    // Return the relevant XML information
    return array('vals' => $vals, 'index' => $index);
}

这部分工作得很好,我可以print_r两个数组并使结果有意义。然而,下面的函数不起作用——至少不是在所有情况下都起作用。如果我对要替换的字段使用某些分隔符,它可以工作,但不是所有时间,我认为这是Word的字符编码或其他格式的问题。

// $templateFile = original, unedited template; $newFile = new file name to be created; $row = array of data to merge in
function mailmerge($templateFile, $newFile, $row) {
  if (!copy($templateFile, $newFile))  // make a duplicate so we dont overwrite the template
    return false; // could not duplicate template
  $xmldata = get_docx_xml($newFile);
  $zip = new ZipArchive();
  if ($zip->open($newFile, ZIPARCHIVE::CHECKCONS) !== TRUE)
    return false; // probably not a docx file
  $file = 'word/document.xml';
  $data = $zip->getFromName($file);
  foreach ($row as $key => $value) {
    $data = str_replace($key, xml_escape($value), $data);
  }
  $zip->deleteName($file);
  $zip->addFromString($file, $data);
  $zip->close();
  return true;
}

所以,而不是使用str_replace(这失败了很多时候),我计划循环$vals数组,我从第一个函数得到,做替换,然后保存结果数组返回到字符串,反过来,回到DOCX zip容器。

虽然我没有找到我的问题的答案,但我已经通过变通解决了这个问题。我有效地使用了一系列substr_replace调用来进行必要的更新。这是我新的和改进的邮件合并功能,如果有人需要这样的东西:

// Merge data into a Word file (mailmerge or custom)
// $templateFile = original, unedited template; $newFile = new file name to be created; $row = array of data to merge in; $delim_start = starting delimiter; $delim_end = ending delimiter
function mailmerge($templateFile, $newFile, $row, $delim_start, $delim_end) {
  if (!copy($templateFile, $newFile))  // make a duplicate so we dont overwrite the template
    return false; // could not duplicate template
  $zip = new ZipArchive();
  if ($zip->open($newFile, ZIPARCHIVE::CHECKCONS) !== TRUE)
    return false; // probably not a docx file
  $file = 'word/document.xml';
  $data = $zip->getFromName($file);
  $currentpos = 0;
  foreach ($row as $key => $value) {
    // Look for a naturally occuring instance of the replacement string (key) and replace as needed
    if (stristr($data, $key)) {
      $currentpos = strpos($data, $key) + strlen($key);
      $data = str_replace($key, xml_escape($value), $data);
    }
    else { // Look for the key's delimiter
      if (stristr($data, $delim_start, $currentpos)) {
        $pos_start = strpos($data, $delim_start, $currentpos);
        // Clear the initial delimiter
        $data = substr_replace($data, '', $pos_start, strlen($delim_start));
        // Now find the actual data (by XML key)
        $datapos_start = (strpos($data, '<w:t>', $pos_start)) + 5;
        $datapos_end = strpos($data, '</w:t>', $datapos_start);
        // Replace the data
        $data = substr_replace($data, xml_escape($value), $datapos_start, ($datapos_end - $datapos_start));
        // Clear the closing delimiter (have to recalculate datapos_end due to the replacement)
        $datapos_end = strpos($data, $delim_end, $datapos_start);
        $data = substr_replace($data, '', $datapos_end, strlen($delim_end));
        // Reset the current posistion variable for the next iteration
        $currentpos = $datapos_end + 6;
      }
    }
  }
  $zip->deleteName($file);
  $zip->addFromString($file, $data);
  $zip->close();
  return true;
}

相关内容

  • 没有找到相关文章

最新更新