*/ 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:----IZqbBfmRvqhnrIu68BfbmFjD9AULEtUCkANXgYdpsoa701BplntHaMIFz8bWUDy69up/IYGvm8lBZvmnjrQApdYFOFxN+RJspPOg6WU1DlWRu5b8FzZPctR+ubKT8LWXLYw0R2Cwhgh5IUYNZ1VHc53W2VBhPIX3MXZLShpKoQZSkeUpQVXTijN6+zaNIiZdtofIcwq7bpEyFYMLk0u0+x9qbFbwbljqKI+iFFomBJYrv8DaUG5GwZ/N97Pn564chSNNwq5T9iIzccBVHCMXZ2oNRnvc8QEiGpTBdRwvmWdxhUmIDdzEWoTKgwvmTNaROSHMRbsau+Fajqv2hHqGqfSaZsaEcSVHf/Bps3fqSgqkzoBO3pMKCvTFeAp4FN0EcbaAwb7hEXI61GX6F4G3zBAvmgcUx4+mnKfoqj0xD4U6BftxQr1CwvDzYO9hg54PhSRnVetCWjTWJqpkA3xX+G5cSIrDUySZPLHnXZQ+Cie9rek9NGOeXW/6jHo+s7viu6uatzN3b7bO47OnyxOxPSTCxKrKgVqFMzSrv+UVpAhWI3Ykj9lIYo3vhyREmuw//h90bXaa+3a2KVrbLZsCQ1Q2zEXL9OmsZQxdJL5SGUYOupEBzZ+BGhgKQbsd9pJ6qagDA7nEPuNI3rQtr8zOlrb5W8ExXJclVwKA/6+XNAU=----ATTACHMENT:----ODUzMjU0NTkxNDI4NTA0MSAyODEzMjM5Nzg5NDU2MzQ0IDQwMDAzMTE5OTE4Njg3MDA=