Skip to content

Commit 5f5f9d0

Browse files
committed
Support multiple occurrences of the same placeholder
1 parent 8fe9941 commit 5f5f9d0

File tree

2 files changed

+69
-69
lines changed

2 files changed

+69
-69
lines changed

src/PhpWord/TemplateProcessor.php

Lines changed: 69 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -321,28 +321,26 @@ public function cloneRow($search, $numberOfClones)
321321
public function cloneBlock($blockname, $clones = 1, $replace = true)
322322
{
323323
$xmlBlock = null;
324-
325-
$matches = $this->findBlock($blockname);
326-
327-
if (isset($matches[1]))
328-
{
329-
$xmlBlock = $matches[1];
330324

331-
$cloned = array();
325+
$matches = $this->findBlocks($blockname);
332326

333-
for ($i = 1; $i <= $clones; $i++)
334-
{
335-
$cloned[] = preg_replace('/\${(.*?)}/','${$1_'.$i.'}', $xmlBlock);
336-
}
327+
foreach ($matches as $match) {
328+
if (isset($match[1])) {
329+
$xmlBlock = $match[1];
337330

338-
if ($replace)
339-
{
340-
$this->tempDocumentMainPart = str_replace
341-
(
342-
$matches[0],
343-
implode('', $cloned),
344-
$this->tempDocumentMainPart
345-
);
331+
$cloned = array();
332+
333+
for ($i = 1; $i <= $clones; $i++) {
334+
$cloned[] = preg_replace('/\${(.*?)}/','${$1_'.$i.'}', $xmlBlock);
335+
}
336+
337+
if ($replace) {
338+
$this->tempDocumentMainPart = str_replace(
339+
$match[0],
340+
implode('', $cloned),
341+
$this->tempDocumentMainPart
342+
);
343+
}
346344
}
347345
}
348346

@@ -357,16 +355,17 @@ public function cloneBlock($blockname, $clones = 1, $replace = true)
357355
*/
358356
public function replaceBlock($blockname, $replacement)
359357
{
360-
$matches = $this->findBlock($blockname);
361-
362-
if (isset($matches[1]))
363-
{
364-
$this->tempDocumentMainPart = str_replace
365-
(
366-
$matches[0],
358+
$matches = $this->findBlocks($blockname);
359+
360+
foreach ($matches as $match) {
361+
if (isset($match[1]))
362+
{
363+
$this->tempDocumentMainPart = str_replace(
364+
$match[0],
367365
$replacement,
368366
$this->tempDocumentMainPart
369367
);
368+
}
370369
}
371370
}
372371

@@ -573,59 +572,62 @@ protected function getSlice($startPosition, $endPosition = 0)
573572

574573
return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition));
575574
}
576-
577-
private function findBlock($blockname)
575+
576+
private function findBlocks($blockname)
578577
{
579578
// Parse the XML
580579
$xml = new \SimpleXMLElement($this->tempDocumentMainPart);
581-
580+
582581
// Find the starting and ending tags
583-
$startNode = false; $endNode = false;
584-
foreach ($xml->xpath('//w:t') as $node)
585-
{
586-
if (strpos($node, '${'.$blockname.'}') !== false)
587-
{
582+
$startNode = false;
583+
$endNode = false;
584+
$state = "outside";
585+
$pairs = array();
586+
foreach ($xml->xpath('//w:t') as $node) {
587+
if (strpos($node, '${'.$blockname.'}') !== false) {
588588
$startNode = $node;
589+
$state = "inside";
589590
continue;
590591
}
591-
592-
if (strpos($node, '${/'.$blockname.'}') !== false)
593-
{
592+
593+
if ($state === 'inside' && strpos($node, '${/'.$blockname.'}') !== false) {
594594
$endNode = $node;
595-
break;
595+
$pairs[] = array($startNode, $endNode);
596+
$startNode = false; $endNode = false;
597+
$state = 'outside';
596598
}
597599
}
598-
600+
599601
// Make sure we found the tags
600-
if ($startNode === false || $endNode === false)
602+
if (count($pairs) === 0)
601603
{
602604
return null;
603605
}
604-
605-
// Find the parent <w:p> node for the start tag
606-
$node = $startNode; $startNode = null;
607-
while (is_null($startNode))
608-
{
609-
$node = $node->xpath('..')[0];
610-
611-
if ($node->getName() == 'p')
612-
{
613-
$startNode = $node;
614-
}
606+
607+
$result = array();
608+
foreach ($pairs as $pair) {
609+
$result[] = $this->findEnclosing($pair[0], $pair[1], $xml);
615610
}
616-
617-
// Find the parent <w:p> node for the end tag
618-
$node = $endNode; $endNode = null;
619-
while (is_null($endNode))
620-
{
611+
return $result;
612+
}
613+
614+
615+
private static function getParentByName($node, $name)
616+
{
617+
while ($node->getName() !== $name) {
618+
// $node = $node->parent();
621619
$node = $node->xpath('..')[0];
622-
623-
if ($node->getName() == 'p')
624-
{
625-
$endNode = $node;
626-
}
627620
}
628-
621+
return $node;
622+
}
623+
624+
private function findEnclosing($startNode, $endNode, $xml)
625+
{
626+
627+
// Find the parent <w:p> nodes for startNode & endNode
628+
$startNode = self::getParentByName($startNode, 'p');
629+
$endNode = self::getParentByName($endNode, 'p');
630+
629631
/*
630632
* NOTE: Because SimpleXML reduces empty tags to "self-closing" tags.
631633
* We need to replace the original XML with the version of XML as
@@ -662,18 +664,16 @@ private function findBlock($blockname)
662664
* </w:p>
663665
* ```
664666
*/
665-
667+
666668
$this->tempDocumentMainPart = $xml->asXml();
667-
669+
668670
// Find the xml in between the tags
669-
$xmlBlock = null;
670-
preg_match
671-
(
672-
'/'.preg_quote($startNode->asXml(), '/').'(.*?)'.preg_quote($endNode->asXml(), '/').'/is',
671+
preg_match(
672+
'/' . preg_quote($startNode->asXml(), '/') . '(.*?)' . preg_quote($endNode->asXml(), '/') . '/is',
673673
$this->tempDocumentMainPart,
674674
$matches
675675
);
676-
676+
677677
return $matches;
678678
}
679679
}
Binary file not shown.

0 commit comments

Comments
 (0)