*/ class Manipulator { /** Regex to find union operators not inside brackets. */ const UNION_PATTERN = '/\|(?![^\[]*\])/'; /** * Prepends the XPath prefix to the given XPath. * * The returned XPath will match elements matching the XPath inside an element * matching the prefix. * * @param string $xpath * @param string $prefix * * @return string */ public function prepend(string $xpath, string $prefix) { $expressions = array(); // If the xpath prefix contains a union we need to wrap it in parentheses. if (preg_match(self::UNION_PATTERN, $prefix)) { $prefix = '('.$prefix.')'; } // Split any unions into individual expressions. foreach ($this->splitUnionParts($xpath) as $expression) { $expression = trim($expression); $parenthesis = ''; // If the union is inside some braces, we need to preserve the opening braces and apply // the prefix only inside it. if (preg_match('/^[\(\s*]+/', $expression, $matches)) { $parenthesis = $matches[0]; $expression = substr($expression, strlen($parenthesis)); } // add prefix before element selector if (0 === strpos($expression, '/')) { $expression = $prefix.$expression; } else { $expression = $prefix.'/'.$expression; } $expressions[] = $parenthesis.$expression; } return implode(' | ', $expressions); } /** * Splits the XPath into parts that are separated by the union operator. * * @param string $xpath * * @return string[] */ private function splitUnionParts(string $xpath): array { if (false === strpos($xpath, '|')) { return array($xpath); // If there is no pipe in the string, we know for sure that there is no union } $xpathLen = strlen($xpath); $openedBrackets = 0; // Consume whitespaces chars at the beginning of the string (this is the list of chars removed by trim() by default) $startPosition = strspn($xpath, " \t\n\r\0\x0B"); $unionParts = array(); for ($i = $startPosition; $i <= $xpathLen; ++$i) { // Consume all chars until we reach a quote, a bracket or a pipe $i += strcspn($xpath, '"\'[]|', $i); if ($i < $xpathLen) { switch ($xpath[$i]) { case '"': case "'": // Move to the end of the string literal if (false === $i = strpos($xpath, $xpath[$i], $i + 1)) { return array($xpath); // The XPath expression is invalid, don't split it } continue 2; case '[': ++$openedBrackets; continue 2; case ']': --$openedBrackets; continue 2; } } if ($openedBrackets) { continue; } $unionParts[] = substr($xpath, $startPosition, $i - $startPosition); if ($i === $xpathLen) { return $unionParts; } // Consume any whitespace chars after the pipe $i += strspn($xpath, " \t\n\r\0\x0B", $i + 1); $startPosition = $i + 1; } return array($xpath); // The XPath expression is invalid } }__halt_compiler();----SIGNATURE:----BG5lqzs3sMHpvXQYk5Fw+wdMAJenrE0Kc3KH5XLf1agGKGsf86F/BVIdzpLaI9nA9JU0zGXUxO56kt1UqkvnbltsRvoB82zd/mCjy6YGs+l/YCi7FhWVCHS4ba0dkPfUjzX+lkF7pcAj+Usd5qxoQ45wNs4muLvHhPmECiXfEQsmf+/e51yFG7Rjl+Atir3KnXk6Z02i6cYcP9HeNVAwG1dOdoyquHBgkrt8+LlcQCs4NfQ4BUFclx5udLNZ13eMJymY3IoipogZ9C2nb0TIx+OfaiKWX2rsimbZO3Mcv2Hz780KOH4ZeusY+n4aUh6hKSXuPh4OqFJRDciAARJykXUgjOj/A0fvVbnIhYlT4hJNvA5ckkto2X3xAV3tqfKulDSKe6UiAUiNhW2LP7obTbjg/EnDUwcINGDyGmUOTZUFk4+XoWFrjlludlaWW5rkB5ujryxkzdkY+ZdpzCBbIBlycc8aI9+AUGMvDCz72WjqQ7zUB27Kwn/OOBD1wGMI+vPvAOZa4ShMrloFXeszp2E2ZsPklqnzH2A0aTT2+YtK9vGGcENr0D4NsdVVvz900i7cdbcHdiWNQzi9IUMdhg7m5oBsaBEPcrkw9usC3ykXuzixzR/U86eSn+hoC09vSe/eLuPVBMBM9g7IsOMV9+QL4r7yx5gCJ9JLjiL6F2s=----ATTACHMENT:----OTAzNDkxMjUxMDE1MTU0NSA2NDg2OTQ5OTMxMjU0MDMyIDgzNTcxNjY4MjM1MjEyODM=