与xml_parse_into_struct相反?

时间:2015-09-02 20:07:33

标签: php xml docx

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

这是我到目前为止所拥有的:

addFromString

那部分工作正常,我可以// $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); } 两个数组并理解结果。但是,以下功能不起作用 - 至少在所有情况下都不起作用。如果我对要替换的字段使用某些分隔符,它可以工作,但不是我假设的所有时间都是Word的字符编码或其他格式的问题。

print_r

所以不是使用str_replace(它在很多时候失败),而是计划循环从第一个函数中获取的$ vals数组,在那里进行替换,然后将生成的数组保存回字符串并且反过来,回到DOCX zip容器。

1 个答案:

答案 0 :(得分:0)

虽然我没有找到问题的答案,但我已通过解决方法解决了问题。实际上,我使用了一系列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;
}