我尝试编写一系列函数,这些函数将提取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容器。
答案 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;
}