@@ -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 ];
330-
331- $ cloned = array ();
332-
333- for ($ i = 1 ; $ i <= $ clones ; $ i ++)
334- {
335- $ cloned [] = preg_replace ('/\${(.*?)}/ ' ,'${$1_ ' .$ i .'} ' , $ xmlBlock );
336- }
337324
338- if ($ replace )
339- {
340- $ this ->tempDocumentMainPart = str_replace
341- (
342- $ matches [0 ],
343- implode ('' , $ cloned ),
344- $ this ->tempDocumentMainPart
345- );
325+ $ matches = $ this ->findBlocks ($ blockname );
326+
327+ foreach ($ matches as $ match ) {
328+ if (isset ($ match [1 ])) {
329+ $ xmlBlock = $ match [1 ];
330+
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,16 @@ 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+ $ this ->tempDocumentMainPart = str_replace (
363+ $ match [0 ],
367364 $ replacement ,
368365 $ this ->tempDocumentMainPart
369366 );
367+ }
370368 }
371369 }
372370
@@ -573,59 +571,62 @@ protected function getSlice($startPosition, $endPosition = 0)
573571
574572 return substr ($ this ->tempDocumentMainPart , $ startPosition , ($ endPosition - $ startPosition ));
575573 }
576-
577- private function findBlock ($ blockname )
574+
575+ private function findBlocks ($ blockname )
578576 {
579577 // Parse the XML
580578 $ xml = new \SimpleXMLElement ($ this ->tempDocumentMainPart );
581-
579+
582580 // 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- {
581+ $ startNode = false ;
582+ $ endNode = false ;
583+ $ state = 'outside ' ;
584+ $ pairs = array ();
585+ foreach ($ xml ->xpath ('//w:t ' ) as $ node ) {
586+ if (strpos ($ node , '${ ' . $ blockname . '} ' ) !== false ) {
588587 $ startNode = $ node ;
588+ $ state = 'inside ' ;
589589 continue ;
590590 }
591-
592- if (strpos ($ node , '${/ ' .$ blockname .'} ' ) !== false )
593- {
591+
592+ if ($ state === 'inside ' && strpos ($ node , '${/ ' . $ blockname . '} ' ) !== false ) {
594593 $ endNode = $ node ;
595- break ;
594+ $ pairs [] = array ($ startNode , $ endNode );
595+ $ startNode = false ;
596+ $ endNode = false ;
597+ $ state = 'outside ' ;
596598 }
597599 }
598-
600+
599601 // Make sure we found the tags
600- if ($ startNode === false || $ endNode === false )
601- {
602+ if (count ($ pairs ) === 0 ) {
602603 return null ;
603604 }
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- }
605+
606+ $ result = array ();
607+ foreach ($ pairs as $ pair ) {
608+ $ result [] = $ this ->findEnclosing ($ pair [0 ], $ pair [1 ], $ xml );
615609 }
616-
617- // Find the parent <w:p> node for the end tag
618- $ node = $ endNode ; $ endNode = null ;
619- while (is_null ($ endNode ))
620- {
621- $ node = $ node ->xpath ('.. ' )[0 ];
622-
623- if ($ node ->getName () == 'p ' )
624- {
625- $ endNode = $ node ;
626- }
610+
611+ return $ result ;
612+ }
613+
614+ private static function getParentByName ($ node , $ name )
615+ {
616+ while ($ node ->getName () !== $ name ) {
617+ $ parents = $ node ->xpath ('.. ' );
618+ $ node = $ parents [0 ];
627619 }
628-
620+
621+ return $ node ;
622+ }
623+
624+ private function findEnclosing ($ startNode , $ endNode , $ xml )
625+ {
626+ // Find the parent <w:p> nodes for startNode & endNode
627+ $ startNode = self ::getParentByName ($ startNode , 'p ' );
628+ $ endNode = self ::getParentByName ($ endNode , 'p ' );
629+
629630 /*
630631 * NOTE: Because SimpleXML reduces empty tags to "self-closing" tags.
631632 * We need to replace the original XML with the version of XML as
@@ -662,18 +663,16 @@ private function findBlock($blockname)
662663 * </w:p>
663664 * ```
664665 */
665-
666+
666667 $ this ->tempDocumentMainPart = $ xml ->asXml ();
667-
668+
668669 // Find the xml in between the tags
669- $ xmlBlock = null ;
670- preg_match
671- (
672- '/ ' .preg_quote ($ startNode ->asXml (), '/ ' ).'(.*?) ' .preg_quote ($ endNode ->asXml (), '/ ' ).'/is ' ,
670+ preg_match (
671+ '/ ' . preg_quote ($ startNode ->asXml (), '/ ' ) . '(.*?) ' . preg_quote ($ endNode ->asXml (), '/ ' ) . '/is ' ,
673672 $ this ->tempDocumentMainPart ,
674673 $ matches
675674 );
676-
675+
677676 return $ matches ;
678677 }
679678}
0 commit comments