Напротив xml_parse_into_struct?

Я пытаюсь написать серию функций, которые будут извлекать document.xml часть файла MS Word DOCX и эффективно объединять серию пар ключ / значение для замены определенных полей шаблона в документе. У меня есть функция, которая использует xml_parse_into_struct чтобы преобразовать текст XML в необходимые массивы, но как только я закончу с заменой текста, мне (предположительно) потребуется использовать ZipArchive метод addFromString создать новый файл document.xml и добавить его в почтовый контейнер DOCX. Но я не уверен, как это сделать, когда я работаю с массивом данных, а не со строкой 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.

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;
}
0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector