@@ -732,8 +732,34 @@ public function getOuterHtml()
732732 */
733733 public function __toString ()
734734 {
735+ return $ this ->getOuterHtml ();
736+ }
735737
736- return $ this ->getOuterHtml ();
738+ /**
739+ * Replace char with null bytes inside (optionaly specified) enclosure
740+ *
741+ * @param string $str
742+ * @param string $search
743+ * @param string $enclosure_open
744+ * @param string $enclosure_close
745+ *
746+ * @return string $str
747+ */
748+ private static function replaceInsideEnclosure ($ str , $ search_char , $ enclosure_open ='( ' , $ enclosure_close =') ' )
749+ {
750+ if ($ str == '' ) {
751+ return $ str ;
752+ }
753+
754+ for ($ i = 0 ; $ i < strlen ($ str ); $ i ++) {
755+ if ($ str [$ i ] === $ search_char && $ i > 0 ) {
756+ if (substr_count ($ str , $ enclosure_open , 0 , $ i ) != substr_count ($ str , $ enclosure_close , 0 , $ i )) {
757+ $ str [$ i ] = "\0" ;
758+ }
759+ }
760+ }
761+
762+ return $ str ;
737763 }
738764
739765 /**
@@ -745,12 +771,14 @@ public function __toString()
745771 */
746772 public static function cssToXpath (string $ path )
747773 {
748- if (strstr ($ path , ', ' )) {
749- $ paths = explode (', ' , $ path );
774+ $ tmp_path = self ::replaceInsideEnclosure ($ path , ', ' );
775+ if (strstr ($ tmp_path , ', ' )) {
776+ $ paths = explode (', ' , $ tmp_path );
750777 $ expressions = array ();
751778
752779 foreach ($ paths as $ path ) {
753- $ xpath = static ::cssToXpath (trim ($ path ));
780+ $ path = str_replace ("\0" , ', ' , $ path ); // restore commas
781+ $ xpath = static ::cssToXpath (trim ($ path ));
754782
755783 if (is_string ($ xpath )) {
756784 $ expressions [] = $ xpath ;
@@ -764,13 +792,7 @@ public static function cssToXpath(string $path)
764792
765793 // replace spaces inside (), to correcly create tokens
766794
767- for ($ i = 0 ; $ i < strlen ($ path ); $ i ++) {
768- if ($ path [$ i ] === ' ' ) {
769- if (substr_count ($ path , '( ' , 0 , $ i ) != substr_count ($ path , ') ' , 0 , $ i )) {
770- $ path [$ i ] = "\0" ;
771- }
772- }
773- }
795+ $ path = self ::replaceInsideEnclosure ($ path , ' ' );
774796
775797 // create and analyze tokens and create segments
776798
@@ -781,7 +803,7 @@ public static function cssToXpath(string $path)
781803 $ relation_tokens = array ('> ' , '~ ' , '+ ' );
782804
783805 foreach ($ tokens as $ key => $ token ) {
784- $ token = str_replace ("\0" , ' ' , $ token ); // restore spaces
806+ $ token = str_replace ("\0" , ' ' , $ token ); // restore spaces
785807
786808 if (!in_array ($ token , $ relation_tokens )) {
787809 $ segment = (object ) array ('selector ' => '' , 'relation_filter ' => false , 'attribute_filters ' => array (), 'pseudo_filters ' => array ());
@@ -872,7 +894,13 @@ private static function transformCssPseudoSelector($expression, array &$new_path
872894 $ expression = preg_replace_callback (
873895 '|not\((.+)\)|i ' ,
874896 function ($ matches ) {
875- return '[not(self:: ' . ltrim (self ::cssToXpath ($ matches [1 ]), '/ ' ) .')] ' ;
897+ $ parts = explode (', ' , $ matches [1 ]);
898+ foreach ($ parts as &$ part ) {
899+ $ part = trim ($ part );
900+ $ part = 'self:: ' .ltrim (self ::cssToXpath ($ part ), '/ ' );
901+ }
902+ $ not_selector = implode (' or ' , $ parts );
903+ return '[not( ' .$ not_selector .')] ' ;
876904 },
877905 $ expression
878906 );
0 commit comments