@@ -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}
0 commit comments