Perform query via xpath expression (using DOMXPath::query)

@param string $expression
@param \DOMNode|null $context_node

@return \DOMNodeList|false
@throws \Exception
965574
public function xpathQuery(string $expression, \DOMNode $context_node=null)
    {
        if ($this->dom_xpath) {
            $node_list = $this->dom_xpath->query($expression, $context_node);

            if ($node_list instanceof \DOMNodeList) {
                return $node_list;
            } elseif ($node_list === false && $context_node) {
                throw new \Exception('Expression '.$expression.' is malformed or contextnode is invalid.');
            } elseif ($node_list === false) {
                throw new \Exception('Expression '.$expression.' is malformed.');
            }
        }

        return false;
    }
250853
public static function filter(array $collection, $expression, array $context = [])
    {
        $language = new ExpressionLanguage();

        $result = [];
        foreach ($collection as $key => $item) {
            if ($language->evaluate($expression, array_merge($context, ['item' => $item, 'key' => $key]))) {
                $result[$key] = $item;
            }
        }

        return $result;
    }
1084773
public function xpath($expression, $wrapNode = true)
    {
        return $this->find($expression, Query::TYPE_XPATH, $wrapNode);
    }
12478
function handleContextNode( $context )
    {
        $contextName = null;
        $messages = array();
        $context_children = $context->childNodes;

        for( $i = 0; $i < $context_children->length; $i++ )
        {
            $context_child = $context_children->item( $i );
            if ( $context_child->nodeType == XML_ELEMENT_NODE )
            {
                if ( $context_child->tagName == "name" )
                {
                    $name_el = $context_child->firstChild;
                    if ( $name_el )
                    {
                        $contextName = $name_el->nodeValue;
                    }
                }
                break;
            }
        }
        if ( !$contextName )
        {
            eZDebug::writeError( "No context name found, skipping context", __METHOD__ );
            return false;
        }
        foreach( $context_children as $context_child )
        {
            if ( $context_child->nodeType == XML_ELEMENT_NODE )
            {
                $childName = $context_child->tagName;
                if ( $childName == "message" )
                {
                    $this->handleMessageNode( $contextName, $context_child );
                }
                else if ( $childName == "name" )
                {
                    /* Skip name tags */
                }
                else
                {
                    eZDebug::writeError( "Unknown element name: $childName", __METHOD__ );
                }
            }
        }
        if ( $contextName === null )
        {
            eZDebug::writeError( "No context name found, skipping context", __METHOD__ );
            return false;
        }
        if ( !isset( $this->CachedMessages[$contextName] ) )
            $this->CachedMessages[$contextName] = array();

        return true;
    }
425825
public function query( $path, $node = NULL )
	{
		if( !$this->xPath )
			throw new Exception( 'No XML loaded yet.' );
		if( $node )
			$nodeList	= $this->xPath->query( $path, $node );
		else
			$nodeList	= $this->xPath->query( $path );
		return $nodeList;
	}
284735
public function xpath(string $xpath_query)
    {
        $result = $this->createChildInstance();

        if (isset($this->document)) {
            $result->xpath_query = $xpath_query;

            if (isset($this->root_instance) || isset($this->xpath_query)) {  // all nodes as context
                foreach ($this->nodes as $node) {
                    if ($result_node_list = $this->xpathQuery('.'.$xpath_query, $node)) {
                        $result->loadDomNodeList($result_node_list);
                    }
                }
            } else { // whole document
                if ($result_node_list = $this->xpathQuery($xpath_query)) {
                    $result->loadDomNodeList($result_node_list);
                }
            }
        }

        return $result;
    }
157386
public function absolutizeAHref($selector = null, $context = null)
    {
        /**
         * @var \DOMElement $item
         */
        if ($selector) {
            foreach ($this->_query->xpath($selector, $context) as $item) {
                if ($item->nodeName === 'a') {
                    $item->setAttribute('href', $this->absolutizeUrl($item->getAttribute('href')));
                } else {
                    $this->absolutizeAHref(null, $item);
                }
            }
        } else {
            foreach ($this->_query->xpath("descendant:://a[not(starts-with(@href, 'http'))]", $context) as $item) {
                $item->setAttribute('href', $this->absolutizeUrl($item->getAttribute('href')));
            }
        }

        return $this;
    }
334380
public function xpath($query)
    {
        $nodes = [];
        /**
         * @var \DOMNode $node
         */
        foreach ($this->_document->getQuery()->xpath($query, $this->_node) as $node) {
            $nodes[$node->getNodePath()] = $node;
        }
        return new SelectorList($this->_document, $nodes);
    }
468448
public String getXPath(NamespaceContext context, String xml, String xPathExpr) {
        return (String) evaluateXpath(context, xml, xPathExpr, null);
    }
620323
public function visit($query, NodeContract $node, string $context)
    {
        if ($node instanceof Nodes\AndNode) {
            $callback = function ($q) use ($node) {
                foreach ($node->getChildren() as $child) {
                    if ($child instanceof Nodes\KeyNode || $child instanceof Nodes\ValueNode) {
                        throw new \Railken\SQ\Exceptions\QuerySyntaxException();
                    }

                    $this->getBuilder()->build($q, $child, Nodes\AndNode::class);
                }
            };

            $context === Nodes\OrNode::class && $query->orWhere($callback);
            $context === Nodes\AndNode::class && $query->where($callback);
        }
    }
236195
public function Match( $item, $context )
	{
		if ( $this->TypeCode == $item->getSchemaType()->TypeCode ) return true;

		switch ( $this->TypeCode )
		{
			case XmlTypeCode::None:
				return false;

			case XmlTypeCode::Item:
				return true;

			case XmlTypeCode::Node:
				return $item->getIsNode();

			case XmlTypeCode::AnyAtomicType:
				return ! $item->getIsNode();

			case XmlTypeCode::UntypedAtomic:
				return ! $item->getIsNode() && $item->GetSchemaType() == XmlSchema::$UntypedAtomic;

			case XmlTypeCode::Document:

				if ( $item instanceof XPathNavigator )
				{
					/**
					 * @var XPathNavigator $nav
					 */
					$nav = $item;
					if ( $nav->getNodeType() == XPathNodeType::Root)
					{
						/**
						 * @var XPathNavigator $cur
						 */
						$cur = $nav->CloneInstance();
						if ( is_null( $this->SchemaElement ) )
						{
							if ( $cur->MoveToChild( XPathNodeType::Element ) && $this->MatchName( $cur, $context ) )
							{
								if ( is_null( $this->SchemaType ) || $this->SchemaType == XmlSchema::$UntypedAtomic )
								{
									return true;
								}
								/**
								 * @var IXmlSchemaInfo $schemaInfo
								 */
								$schemaInfo = $cur->getSchemaInfo();
								if ( ! is_null( $this->schemaInfo ) )
								{
									if ( DOMSchemaType::IsDerivedFrom( $schemaInfo->getSchemaType(), $this->SchemaType, XmlSchemaDerivationMethod::Empty_ ) )
										return ! $schemaInfo->getIsNil() || $this->Nillable;
								}
								else
								{
									return DOMSchemaType::IsDerivedFrom( XmlSchema::$UntypedAtomic, $this->SchemaType, XmlSchemaDerivationMethod::Empty_ );
								}
							}
						}
						else
						{
							if ( ! $cur->MoveToChild( XPathNodeType::Element ) )
							{
								return false;
							}

							/**
							 * @var IXmlSchemaInfo $schemaInfo
							 */
							$schemaInfo = $cur->getSchemaInfo();
							if ( ! is_null( $schemaInfo ) )
							{
								return $schemaInfo->getSchemaElement()->QualifiedName->equals( $this->SchemaElement->QualifiedName );
							}
						}
					}
				}
				break;

			case XmlTypeCode::Element:

				if ( $item instanceof XPathNavigator )
				{
					/**
				   	 * @var XPathNavigator $nav
				   	 */
					$nav = $item;
					if ( $nav->getNodeType() == XPathNodeType::Element )
					{
						if ( is_null( $this->SchemaElement ) )
						{
							if ( $this->MatchName( $nav, $context ) )
							{
								if ( is_null( $this->SchemaType ) || $this->SchemaType == XmlSchema::$UntypedAtomic )
								{
									return true;
								}

								/**
								 * @var IXmlSchemaInfo $schemaInfo
								 */
								$schemaInfo = $nav->getSchemaInfo();
								if ( is_null( $schemaInfo ) )
								{
									return DOMSchemaType::IsDerivedFrom( XmlSchema::$UntypedAtomic, $this->SchemaType, XmlSchemaDerivationMethod::Empty_ );
								}
								else
								{
									if ( DOMSchemaType::IsDerivedFrom( $schemaInfo->getSchemaType(), $this->SchemaType, XmlSchemaDerivationMethod::Empty_ ) )
									{
										return ! $schemaInfo->getIsNil() || $this->Nillable;
									}
								}
							}
						}
						else
						{
							/**
							 * @var IXmlSchemaInfo $schemaInfo
							 */
							$schemaInfo = $nav->getSchemaInfo();
							if ( ! is_null( $schemaInfo ) )
								return $schemaInfo->getSchemaElement()->QualifiedName->equals( $this->SchemaElement->QualifiedName );
						}
					}
				}
				break;

			case XmlTypeCode::Attribute:

				if ( $item instanceof XPathNavigator )
				{
					/**
					 * @var XPathNavigator $nav
					 */
					$nav = $item;
					if ( $nav->getNodeType() == XPathNodeType::Attribute )
					{
						if ( is_null( $this->SchemaAttribute ) )
						{
							if ( $this->MatchName( $nav, $context ) )
							{
								if ( is_null( $this->SchemaType ) || $this->SchemaType == XmlSchema::$UntypedAtomic )
								{
									return true;
								}
								/**
								 * @var IXmlSchemaInfo $schemaInfo
								 */
								$schemaInfo = $nav->getSchemaInfo();
								if ( is_null( $schemaInfo ) )
									return DOMSchemaType::IsDerivedFrom( XmlSchema::$UntypedAtomic, $this->SchemaType, XmlSchemaDerivationMethod::Empty_ );
								else
									return DOMSchemaType::IsDerivedFrom( $schemaInfo->getSchemaType(), $this->SchemaType, XmlSchemaDerivationMethod::Empty_ );
							}
						}
						else
						{
							/**
							 * @var IXmlSchemaInfo $schemaInfo
							 */
							$schemaInfo = $nav->getSchemaInfo();
							if ( ! is_null( $schemaInfo ) )
								return $schemaInfo->getSchemaAttribute()->QualifiedName->equals( $this->SchemaAttribute->QualifiedName );
						}
					}
				}
				break;

			case XmlTypeCode::ProcessingInstruction:

				if ( $item instanceof XPathNavigator )
				{
					/**
					 * @var XPathNavigator $nav
					 */
					$nav = $item;
					return ( $nav->getNodeType() == XPathNodeType::ProcessingInstruction && ( $this->NameTest->IsNameWildcard() || $this->NameTest->localName == $nav->getLocalName() ) );
				}
				break;

			case XmlTypeCode::Comment:

				if ( $item instanceof XPathNavigator )
				{
					/**
					 * @var XPathNavigator $nav
					 */
					$nav = $item;
					return $nav->getNodeType() == XPathNodeType::Comment;
				}
				break;

			case XmlTypeCode::Text:

				if ( $item instanceof XPathNavigator )
				{
					/**
					 * @var XPathNavigator $nav
					 */
					$nav = $item;
					return $nav->getNodeType() == XPathNodeType::Text || $nav->getNodeType() == XPathNodeType::SignificantWhitespace;
				}
				break;

			case XmlTypeCode::PositiveInteger:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					case XmlTypeCode::Byte:
					case XmlTypeCode::Short:
					case XmlTypeCode::Int:
					case XmlTypeCode::Integer:
						return $item->getValueAsInt() >= 0;

					case XmlTypeCode::Long:
						return false;
				}
				break;

			case XmlTypeCode::NegativeInteger:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					case XmlTypeCode::Byte:
					case XmlTypeCode::Short:
					case XmlTypeCode::Int:
					case XmlTypeCode::Integer:
						return $item->getValueAsInt() <= 0;

					case XmlTypeCode::Long:
						return false;
				}
				break;

			case XmlTypeCode::NonPositiveInteger:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					case XmlTypeCode::Byte:
					case XmlTypeCode::Short:
					case XmlTypeCode::Int:
					case XmlTypeCode::Long:
					case XmlTypeCode::Integer:
						return $item->getValueAsInt() <= 0;
				}
				break;

			case XmlTypeCode::NonNegativeInteger:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					case XmlTypeCode::Byte:
					case XmlTypeCode::Short:
					case XmlTypeCode::Int:
					case XmlTypeCode::Integer:
						return $item->getValueAsInt() >= 0;

					case XmlTypeCode::Long:
						return $item->getValueAsLong() == 0;

					case XmlTypeCode::UnsignedByte:
					case XmlTypeCode::UnsignedShort:
					case XmlTypeCode::UnsignedInt:
					case XmlTypeCode::UnsignedLong:
						return true;
				}
				break;

			case XmlTypeCode::Int:
			case XmlTypeCode::Byte:
			case XmlTypeCode::Short:
			case XmlTypeCode::Long:
			case XmlTypeCode::Integer:
			case XmlTypeCode::UnsignedLong:
			case XmlTypeCode::UnsignedInt:
			case XmlTypeCode::UnsignedByte:
			case XmlTypeCode::UnsignedShort:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					case XmlTypeCode::Byte:
					case XmlTypeCode::Short:
					case XmlTypeCode::Int:
					case XmlTypeCode::Long:
					case XmlTypeCode::Integer:
					case XmlTypeCode::UnsignedByte:
					case XmlTypeCode::UnsignedShort:
					case XmlTypeCode::UnsignedInt:
					case XmlTypeCode::UnsignedLong:
						return true;

					case XmlTypeCode::Decimal:
						// BMS 2017-07-20 Changed result
						/**
						 * @var DecimalValue $dec
						 */
						$dec = $item->getTypedValue();
						return $dec->getIntegerPart() == $dec->getValue();
						// BMS 2017-07-10 Changed result
						return false;
						return ! $item->ValueAs( Types::$DecimalType, $context->NamespaceManager )->getIsDecimal();

					case XmlTypeCode::Double:
						// BMS 2017-07-10 Changed result
						return false;
						$value = $item->getTypedValue(); // ->ValueAs( Types::$DoubleType );
						return $value == floor( $value );
				}
				break;

			case XmlTypeCode::Entity:
				return	( $item->GetSchemaType()->TypeCode == XmlTypeCode::String ) ||
						( $item->GetSchemaType()->TypeCode == XmlTypeCode::Entity );

			// In PHP these are synonymous
			// BMS 2017-07-10 Changed result
			case XmlTypeCode::Float:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					// Note the order of these cases is significant
					// If the order is different then float will be
					// reported as an instance of double and will fail
					// test instanceof49 in the exprSeqTypes test set.
					case XmlTypeCode::Float:
						return true;

					case XmlTypeCode::Double:
						if ( is_nan( $item->getTypedValue() ) )
						{
							return true;
						}
				}
				break;

			// BMS 2017-07-10 Changed result
			case XmlTypeCode::Double:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					case XmlTypeCode::Double:
						return true;
				}
				break;

			// BMS 2017-07-10 Changed result
			case XmlTypeCode::Decimal:
				switch ( $item->GetSchemaType()->TypeCode )
				{
					case XmlTypeCode::Byte:
					case XmlTypeCode::Short:
					case XmlTypeCode::Int:
					case XmlTypeCode::Long:
					case XmlTypeCode::Integer:
					case XmlTypeCode::UnsignedByte:
					case XmlTypeCode::UnsignedShort:
					case XmlTypeCode::UnsignedInt:
					case XmlTypeCode::UnsignedLong:
					case XmlTypeCode::Decimal:
						return true;
				}
				break;

			default:
				{
					$schemaType = $item->getSchemaType();
					if ( ! is_null( $schemaType ) )
					{
						// BMS 2017-09-03	Added this condition. The XPath documentation indicates that an
						//					untyped type can be matched with any other type.
						// https://www.w3.org/TR/xpath-functions/#casting-from-primitive-to-primitive
						if ( $schemaType->TypeCode == XmlTypeCode::UntypedAtomic )
						{
							return true;
						}
						return DOMSchemaType::IsDerivedFrom( $schemaType, $this->SchemaType, XmlSchemaDerivationMethod::Empty_ );
					}
				}
				break;
		}
		return false;
	}
537821
@Nullable
    public static Node findNode(@NotNull final Node rootNode, @NotNull final XPath xPath,
            @NotNull final String expression) {
        Contract.requireArgNotNull("rootNode", rootNode);
        Contract.requireArgNotNull("xPath", xPath);
        Contract.requireArgNotNull("expression", expression);
        try {
            return (Node) xPath.compile(expression).evaluate(rootNode, XPathConstants.NODE);
        } catch (final XPathExpressionException ex) {
            throw new RuntimeException("Failed to read node: " + expression, ex);
        }
    }
867806
public function evaluate($expression, Context $context)
    {
        $expression = trim($expression);
        $identifier = md5($expression);
        $functionName = 'expression_' . $identifier;
        if (isset($this->evaluatedExpressions[$functionName])) {
            return $this->evaluateAndUnwrap($this->evaluatedExpressions[$functionName], $context);
        }

        $functionDeclaration = $this->expressionCache->get($functionName);
        if (!$functionDeclaration) {
            $functionDeclaration = $this->generateEvaluatorCode($expression);
            $this->expressionCache->set($functionName, $functionDeclaration);
        }

        $expressionFunction = eval($functionDeclaration);
        $this->evaluatedExpressions[$functionName] = $expressionFunction;
        return $this->evaluateAndUnwrap($expressionFunction, $context);
    }
756117
public function elemMatch($expression) : self
    {
        return $this->operator('$elemMatch', $expression instanceof Expr ? $expression->getQuery() : $expression);
    }
475482
public static NodeList evaluateXpathExpression(Document dom, String xpathExpr)
			throws XPathExpressionException {
		XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression expr = xpath.compile(xpathExpr);
		Object result = expr.evaluate(dom, XPathConstants.NODESET);
		return (NodeList) result;
	}
38022
public function parse(Context $context) {
	    $this->context = $context;
		$this->viewElement = $context->tag;

		//Interpret an empty expression as boolean false.
		if(trim($this->expression) == '') {
		  $this->pushOperand(new TokenLiteral(false));
		  return true;
		}

		$char = '';

		try {
			$expressionSize = strlen($this->expression);
			for($this->parsingPosition = 0; $this->parsingPosition < $expressionSize; ++ $this->parsingPosition) {
				$char = $this->expression[$this->parsingPosition];
				$this->currentState->input($this, $char);
			}

			$this->currentState->endOfInput($this);

			while(count($this->stackOperators)) {
				$operator = array_pop($this->stackOperators);
				$nbOperands = $operator->getNumOperands();
				if($nbOperands) {
					// Check that we have enough operands on the stack.
					if (count($this->stackRP) < $nbOperands) {
						throw new LexerSyntaxErrorException('Missing operand', $this->getViewFile(), $this->getViewLine());
					}
					$operator->setOperands(array_splice($this->stackRP, count($this->stackRP) - $nbOperands, $nbOperands));
				}
				$this->stackRP[] = $operator;
				if($operator instanceof TokenFunction) {
									array_pop($this->stackFunctions);
				}
			}
		}

		// Enrich the Lexer parsing and tokenizing exceptions with template file and line
		catch (LexerUnbalancedParenthesesException $exception) {
		    throw new LexerUnbalancedParenthesesException($exception->getMessage(), $this->getViewFile(), $this->getViewLine());
        } catch (LexerSyntaxErrorException $exception) {
		    throw new LexerSyntaxErrorException($exception->getMessage(), $this->getViewFile(), $this->getViewLine());
        } catch (Exception $exception) {
			$errorMsg = "Unexpected character: $char at position: {$this->parsingPosition} in expression: {$this->expression}.";
			throw new LexerUnexpectedCharException($errorMsg, $this->getViewFile(), $this->getViewLine());
		}

		if( (count($this->stackOperators) > 0) ||
				(count($this->stackFunctions) > 0) ||
				(count($this->stackRP) != 1)
			)
		{
			$message = $this->getViewFile() . '(' . $this->getViewLine() . '): Syntax error in expression: ' . $this->expression;
			throw new LexerSyntaxErrorException($message,
					$this->getViewFile(),
					$this->getViewLine());
		}

		// Check for unbalanced parentheses:
		if( ($this->stackRP[0] instanceof TokenFunction) &&
		    (! $this->stackRP[0]->isClosed())
		)
		{
		  $message = $this->getViewFile() . '(' . $this->getViewLine() . '): Unbalanced parentheses in expression: ' . $this->expression;
		  throw new LexerUnbalancedParenthesesException($message,
		    $this->getViewFile(),
		    $this->getViewLine());
		}

		return true;
	}
1370786
public static function evaluateEelExpression($expression, EelEvaluatorInterface $eelEvaluator, array $contextVariables, array $defaultContextConfiguration = [])
    {
        $matches = null;
        if (!preg_match(Package::EelExpressionRecognizer, $expression, $matches)) {
            throw new Exception('The EEL expression "' . $expression . '" was not a valid EEL expression. Perhaps you forgot to wrap it in ${...}?', 1410441849);
        }

        $defaultContextVariables = self::getDefaultContextVariables($defaultContextConfiguration);
        $contextVariables = array_merge($defaultContextVariables, $contextVariables);

        if (isset($contextVariables['q'])) {
            throw new Exception('Context variable "q" not allowed, as it is already reserved for FlowQuery use.', 1410441819);
        }

        $contextVariables['q'] = function ($element) {
            return new FlowQuery\FlowQuery(is_array($element) || $element instanceof \Traversable ? $element : [$element]);
        };

        $context = new ProtectedContext($contextVariables);
        $context->whitelist('q');

        return $eelEvaluator->evaluate($matches['exp'], $context);
    }