diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index e7a8d039c4..63b918131f 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -362,18 +362,16 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) */ public function replaceBlock($blockname, $replacement) { - preg_match( - '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', - $this->tempDocumentMainPart, - $matches - ); - - if (isset($matches[3])) { - $this->tempDocumentMainPart = str_replace( - $matches[2] . $matches[3] . $matches[4], - $replacement, - $this->tempDocumentMainPart - ); + $matches = $this->findBlock($blockname); + + if (isset($matches[1])) + { + $this->temporaryDocumentMainPart = str_replace + ( + $matches[0], + $replacement, + $this->temporaryDocumentMainPart + ); } } @@ -584,4 +582,107 @@ protected function getSlice($startPosition, $endPosition = 0) return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition)); } + + private function findBlock($blockname) + { + // Parse the XML + $xml = new \SimpleXMLElement($this->temporaryDocumentMainPart); + + // Find the starting and ending tags + $startNode = false; $endNode = false; + foreach ($xml->xpath('//w:t') as $node) + { + if (strpos($node, '${'.$blockname.'}') !== false) + { + $startNode = $node; + continue; + } + + if (strpos($node, '${/'.$blockname.'}') !== false) + { + $endNode = $node; + break; + } + } + + // Make sure we found the tags + if ($startNode === false || $endNode === false) + { + return null; + } + + // Find the parent node for the start tag + $node = $startNode; $startNode = null; + while (is_null($startNode)) + { + $node = $node->xpath('..')[0]; + + if ($node->getName() == 'p') + { + $startNode = $node; + } + } + + // Find the parent node for the end tag + $node = $endNode; $endNode = null; + while (is_null($endNode)) + { + $node = $node->xpath('..')[0]; + + if ($node->getName() == 'p') + { + $endNode = $node; + } + } + + /* + * NOTE: Because SimpleXML reduces empty tags to "self-closing" tags. + * We need to replace the original XML with the version of XML as + * SimpleXML sees it. The following example should show the issue + * we are facing. + * + * This is the XML that my document contained orginally. + * + * ```xml + * + * + * + * + * + * + * + * ${CLONEME} + * + * + * ``` + * + * This is the XML that SimpleXML returns from asXml(). + * + * ```xml + * + * + * + * + * + * + * + * ${CLONEME} + * + * + * ``` + */ + + $this->temporaryDocumentMainPart = $xml->asXml(); + + // Find the xml in between the tags + $xmlBlock = null; + preg_match + ( + '/'.preg_quote($startNode->asXml(), '/').'(.*?)'.preg_quote($endNode->asXml(), '/').'/is', + $this->temporaryDocumentMainPart, + $matches + ); + + return $matches; + } }