Converts a node to an XPath query

@param VariableSet $variableSet
@param FactVariableBinding $factVariableBinding
@return string
332503
public function toQuery( $variableSet, $factVariableBinding )
	{
		$expressions = array();

		// Include the qnames if being called as part of a boolean filter or there are qname expressions
		if ( $this->inBoolean || $this->qnameExpressions )
		foreach ( $this->qnames as $qname )
		{
			$name = qname( $qname );
			$expressions[] = "(fn:node-name(..) eq fn:QName('{$name->namespaceURI}','{$name->localName}'))";
		}

		foreach ( $this->qnameExpressions as $qnameExpression )
		{
			$expressions[] = "(fn:node-name(..) eq {$qnameExpression})";
		}

		return implode( " or ", $expressions );
	}
891922
public function validate( $variableSet, $nsMgr )
	{
		if ( $this->qnameExpressions )
		{
			foreach ( $this->qnameExpressions as $qnameExpression )
			{
				try
				{
					$xpath2Expression = XPath2Expression::Compile( $qnameExpression, $nsMgr );
					if ( parent::checkForCoverXFIFunctionUse( $qnameExpression, $xpath2Expression ) )
					{
						return false;
					}

					$this->qnameXPath2Expressions[] = $xpath2Expression;
				}
				catch ( XPath2Exception $ex )
				{
					\XBRL_Log::getInstance()->formula_validation( "Concept name filter", "Failed to compile qname expression",
						array(
							'qname expression' => $qnameExpression,
							'error' => $ex instanceof XPath2Exception ? ( $ex->ErrorCode == 'XPST0017' ? "xbrlve:noCustomFunctionSignature" : $ex->ErrorCode ) : get_class( $ex ),
							'reason' => $ex->getMessage()
						)
					);
				}
				catch ( \Exception $ex )
				{
					// BMS 2018-03-27 Test 21201 V-02 requires that this compile failure return xbrlve:noCustomFunctionSignature
					//				  because the custom function my-own:ending-balance does not exist
					\XBRL_Log::getInstance()->formula_validation( "Concept name filter", "Failed to compile qname expression",
						array(
							'qname expression' => $qnameExpression,
							'error' => $ex instanceof XPath2Exception ? ( $ex->ErrorCode == 'XPST0017' ? "err:XPST0017" : $ex->ErrorCode ) : get_class( $ex ),
							'reason' => $ex->getMessage()
						)
					);
				}
			}
		}

		return true;
	}
170204
public function parseLiteral($valueNode, array $variables = null): EntityID
    {
        $value = (string) parent::parseLiteral($valueNode);

        return $this->createEntityID($value);
    }
438228
public function getBindingsAsVars( $vars = array() )
	{
		// $vars = array_merge( $existingVars, $this->parameters );
		$vars = $this->getParametersAsVars( $vars );

		foreach( $this->factVariableBindings as $bindingQName => /** @var \XBRL\Formulas\factVariableBinding $varBinding */ $varBinding )
		{
			if ( $varBinding->isFallback )
			{
				$current = $varBinding->yieldedFact;
			}
			else
			{
				// Using current makes sure the fact is set and the binding variables are correct
				if ( ! $varBinding->valid() ) $varBinding->rewind();
				$current = $varBinding->current();
			}
			if ( $current instanceof XPath2NodeIterator ) $current->Reset();
			$vars[ $bindingQName ] = $current;
			$vars = array_merge( $vars, $varBinding->getAdditionalVars() );
		}

		foreach( $this->generalVariableBindings as $bindingQName => /** @var VariableBinding $varBinding */ $varBinding )
		{
			// Using current makes sure the fact is set and the binding variables are correct
			// $vars[ $bindingQName ] = $this->variablesByQName[ $bindingQName ]->bindAsSequence ? $varBinding->facts : $varBinding->current();
			if ( ! $varBinding->valid() ) $varBinding->rewind();
			$current = $varBinding->current();
			if ( $current instanceof XPath2NodeIterator )
			{
				// BMS 2018-04-04 Test 0023 V-03 fails because the vars are being reset presumably because a var is not a clone
				$current = $current->CloneInstance();
				$current->Reset();
			}
			else if ( $current instanceof XPathNavigator)
			{
				$current = $current->CloneInstance();
			}
			$vars[ $bindingQName ] = $current;
		}

		return $vars;
	}
1285907
public function getValue( $variableSet, $evaluationResult, $log )
	{
		$aspect = $variableSet->aspectModel == 'dimensional'
			? ( $this->occ == 'segment' ? ASPECT_NON_XDT_SEGMENT : ASPECT_NON_XDT_SCENARIO )
			: ( $this->occ == 'segment' ? ASPECT_COMPLETE_SEGMENT : ASPECT_COMPLETE_SCENARIO );

		$sourceFact = $variableSet->getSourceFact( $this->source, $evaluationResult, $aspect, $log );
		if ( ! $sourceFact ) return null;
		$contextRef = FactValues::getContextRef( $sourceFact );
		if ( ! $contextRef ) return null;
		$context = $variableSet->xbrlInstance->getContext( $contextRef );
		// $component = isset( $context['entity'][ $this->occ ]['member'] )
		// 	? $context['entity'][ $this->occ ]['member']
		// 	: array();
		$components = array();
		if ( ! $this->select ) return $components;

		$componentNodes = $this->evaluateXPath( $variableSet, "{$this->select}", array( $this->getSourceName() => $sourceFact ) );

		foreach ( $componentNodes as $node )
		{
			if ( ( $this->occ == 'scenario' || $this->occ == 'segment' ) &&
				 $node->getNamespaceURI() == \XBRL_Constants::$standardPrefixes[ STANDARD_PREFIX_XBRLDI] )
			{
				$log->formula_validation( "OCC XPath", "The result of the XPath query is not consistent with ",
					array(
						'occ' => $this->occ,
						'xpath' => $this->select,
						'error' => 'xbrlfe:badSubsequentOCCValue'
					)
				);
			}
			$components[] = array( 'name' => $node->getName(), 'member' => '' );
		}

		return $components;
	}
1208621
public static function getDimensionsForFact( $variableSet, $fact )
	{
		$contextRef = FactValues::getContextRef( $fact );
		return FactValues::getDimensionsInContextRef( $variableSet, $contextRef );
	}
186384
public function getValue( $variableSet, $evaluationResult, $log )
	{
		$numerators = array();
		$denominators = array();
		$unitRef = "";

		// Create a list of numerators and denominators
		if ( $this->augment )
		{
			$this->getFactorsFromSource( $this->source, $variableSet, $evaluationResult, $log, $numerators, $denominators, $unitRef );
		}

		foreach ( $this->multiplyBy as $numerator )
		{
			$hasMeasure = isset( $numerator['measure'] ) && $numerator['measure'];

			if ( ! $hasMeasure && isset( $numerator['source'] ) )
			{
				$this->getFactorsFromSource( $numerator['source'], $variableSet, $evaluationResult, $log, $numerators, $denominators );
			}

			if ( $hasMeasure )
			{
				// This is an expression that needs evaluating
				$result = $this->evaluateXPath( $variableSet, "{$numerator['measure']} cast as xs:string", $evaluationResult['vars'] );
				$numerators[] = $result->getValue();
			}
		}

		foreach ( $this->divideBy as $denominator )
		{
			$hasMeasure = isset( $denominator['measure'] ) && $denominator['measure'];

			if ( ! $hasMeasure && isset( $denominator['source'] ) )
			{
				$this->getFactorsFromSource( $denominator['source'], $variableSet, $evaluationResult, $log, $denominators, $numerators );
			}

			if ( $hasMeasure )
			{
				// This is an expression that needs evaluating
				$result = $this->evaluateXPath( $variableSet, "{$denominator['measure']} cast as xs:string", $evaluationResult['vars'] );
				$denominators[] = $result->getValue();
			}
		}

		// Cancel mutual numerators and denominators
		$this->cancel( $numerators, $denominators );

		// Return an array appropriately structured
		$result = array();
		if ( ! $denominators )
		{
			if ( count( $numerators ) == 1 )
			{
				$result = reset( $numerators );
			}
			else
			{
				$result = array( 'measures' => $numerators );
			}
		}
		else
		{
			$result = array(
				'divide' => array( 'numerator' => $numerators, 'denominator' => $denominators )
			);
		}

		if ( ! $unitRef ) $unitRef = "unit";
		return array( $unitRef => $result );
	}
855853
public function toQuery( $variableSet, $factVariableBinding )
	{
		if ( ! $this->substitutionGroups )
		{
			return null;
		}

		$clauses = array();

		if ( isset( $this->substitutionGroups['qnames'] ) && $this->substitutionGroups['qnames'] )
		foreach ( $this->substitutionGroups['qnames'] as $qname )
		{
			$name = qname( $qname );
			$clauses[] = $this->strict
				? "fn:QName('{$name->namespaceURI}','{$name->localName}') eq (xfi:concept-substitutions(fn:node-name(.)))[1]"
				: "fn:QName('{$name->namespaceURI}','{$name->localName}') = xfi:concept-substitutions(fn:node-name(.))";
		}

		if ( isset( $this->substitutionGroups['qnameExpressions'] ) && $this->substitutionGroups['qnameExpressions'] )
		foreach ( $this->substitutionGroups['qnameExpressions'] as $qnameExpression )
		{
			$clauses[] = $this->strict
				? "{$qnameExpression} eq (xfi:concept-substitutions(fn:node-name(.)))[1]"
				: "{$qnameExpression} = xfi:concept-substitutions(fn:node-name(.))";
		}

		return implode( " or ", $clauses );

	}
1136425
private function getSourceFact( $variableSet, $evaluationResult, $log )
	{
		$sourceQName = null;

		if ( count( $this->qname ) )
		{
			$sourceQName = new QName( $this->qname[0]['originalPrefix'], $this->qname[0]['namespace'], $this->qname[0]['name'] );
			if ( ! $sourceQName ) return null;
		}
		elseif ( count( $this->qnameExpression ) )
		{
			$qname = $this->evaluateXPath( $variableSet, $this->qnameExpression[0], $evaluationResult['vars'] );
			if ( $qname instanceof XPath2Item )
			{
				$qname = $qname->getTypedValue();
			}
			if ( ! $qname ) return null;
			$sourceQName = new QName( $qname->Prefix, $qname->NamespaceUri, $qname->LocalName );
		}
		else
		{
			return null;
		}

		// OK, got the source fact but it might be a variable in which case the value of the variable will be required
		if ( isset( $variableSet->variablesByQName[ $sourceQName->clarkNotation() ] ) )
		{
			if ( ! isset( $evaluationResult['vars'][ $sourceQName->clarkNotation() ] ) )
			{
				$log->formula_validation( "Concept aspect", "Unable to find variable",
					array(
						'variable' => $sourceQName->clarkNotation(),
						'error' => 'xbrlfe:incompleteConceptRule'
					)
				);
			}
			// Get the evaluation value for this variable
			$fact = $evaluationResult['vars'][ $sourceQName->clarkNotation() ];
			if ( $fact instanceof XPath2NodeIterator )
			{
				// Get the first fact
				while (true)
				{
					foreach ( $fact as $node )
					{
						if ( ! $node instanceof DOMXPathNavigator ) continue;
						$fact = $node;
						break 2;
					}

					$fact = null;
					break;
				}
			}

			if ( $fact instanceof XPathNavigator )
			{
				$sourceQName = new QName( $fact->getPrefix(), $fact->getNamespaceURI(), $fact->getLocalName() );
			}
			else
			{
				$log->formula_validation( "Concept aspect", "The variable reference does not point to a result node",
					array(
						'variable' => $sourceQName->clarkNotation(),
						'error' => 'xbrlfe:incompleteConceptRule'
					)
				);
			}
		}
		return $sourceQName;
	}
604453
public function toQuery( $variableSet, $factVariableBinding )
	{
		/**
		 * These are the arguments to the xfi:concept-relationships function
	     * #source
		 * #linkrole
		 * #arcrole
		 * #axis
		 * #generations
		 * #linkname
		 * #arcname
		 */

		$source = $this->variable
					? ( "fn:node-name(" . ( $this->variable['originalPrefix'] ? "\${$this->variable['originalPrefix']}:$this->variable['name']" : "\${$this->variable['name']}" ) . ")" )
					: ( $this->qnameExpression
							? $this->qnameExpression
							: "QName('" . qname($this->qname, $variableSet->nsMgr->getNamespaces())->namespaceURI . "', '" . qname($this->qname, $variableSet->nsMgr->getNamespaces())->localName . "')"
					  );

		$linkrole = $this->linkrole
					? "'{$this->linkrole}'"
					: ( $this->linkroleExpression
							? $this->linkroleExpression
							: "()"
					  );

		$arcrole = $this->arcrole
					? "'{$this->arcrole}'"
					: ( $this->arcroleExpression
							? $this->arcroleExpression
							: "()"
					  );

		$axis = "{$this->axis}";
		$generations = $this->generations ? $this->generations : "()";

		$linkname = $this->linkname
					? "'{$this->linkname}'"
					: ( $this->linknameExpression
							? $this->linknameExpression
							: "()"
					  );

		$arcname = $this->arcname
					? "'{$this->arcname}'"
					: ( $this->arcnameExpression
							? $this->arcnameExpression
							: "()"
					  );

		$test = $this->test
					? $this->test
					: "true()";

		// Alternative line end goes here (for query formatting)
		$le = "";

		$query = "( $le" .
				 "	( $le" .
				 "		some \$relationship in $le" .
				 "			xfi:concept-relationships( $le" .
				 "				$source, $le" .
				 "				$linkrole, $le" .
				 "				$arcrole, $le" .
				 "				" . str_replace( "-or-self", "", "'$axis'" ) . ",$le" .
		//		 "				fn:replace($axis,'-or-self',''), $le" .
				 "				$generations, $le" .
				 "				$linkname, $le" .
				 "				$arcname $le" .
				 "			) $le" .
				 "		satisfies $le" .
				 "			( $le" .
				 "				\$relationship[$test] and $le" .
				 "				(fn:node-name(.) eq $le" .
             	 "					( $le" .
             	 "						if (matches('$axis','ancestor|parent')) $le" .
              	 "						then xfi:relationship-from-concept(\$relationship) $le" .
              	 "						else xfi:relationship-to-concept(\$relationship) $le" .
              	 "					) $le" .
              	 "				) $le" .
              	 "			) $le" .
              	 "  ) $le";

		$clause1 = "" .
				 "	or $le" .
				 "	( $le" .
		//		 "		fn:starts-with($axis,'sibling') and $le" .
				 "		fn:empty( $le" .
				 "			xfi:concept-relationships( $source, $linkrole, $arcrole, 'parent', 1, $linkname, $arcname) $le" .
				 "		) and $le" .
				 "		fn:empty( $le" .
				 "			xfi:concept-relationships( fn:node-name(.), $linkrole, $arcrole, 'parent', 1, $linkname, $arcname) $le" .
				 "		) and $le" .
				 "		fn:exists( $le" .
				 "			xfi:concept-relationships( fn:node-name(.), $linkrole, $arcrole, 'child', 1, $linkname, $arcname) $le" .
				 "		) and $le" .
				 "		(fn:node-name(.) ne $source) $le" .
				 "	) $le";

		$clause2 = "" .
				 "	or $le" .
				 "	( $le" .
		//		 "		fn:ends-with($axis,'-or-self') $le" .
		//		 " 		and $le" .
		//		 "		( $le" .
				 "			if ( QName('http://www.xbrl.org/2008/function/instance','root') eq $source) $le" .
				 "			then $le" .
				 "			( $le" .
				 "				fn:empty( $le" .
				 "					xfi:concept-relationships( fn:node-name(.), $linkrole, $arcrole, 'parent', 1, $linkname, $arcname) $le" .
				 "				) and $le" .
				 "				fn:exists( $le" .
				 "					xfi:concept-relationships( fn:node-name(.), $linkrole, $arcrole, 'child', 1, $linkname, $arcname) $le" .
				 "				) $le" .
				 "			) $le" .
				 "			else $le" .
				 "			( $le" .
				 "				fn:node-name(.) eq $source $le" .
				 "			) $le" .
		//		 "		) $le" .
				 "  ) $le";

		$query = $query . ( \XBRL::startsWith( $axis, 'sibling' ) ? $clause1 : "" ) . ( \XBRL::endsWith( $axis, '-or-self' ) ? $clause2 : "" );
		$query .= ") $le";
		if ( empty( $le ) )
		{
			$query = preg_replace( "/\s\t+/", " ", $query );
		}
		echo $query;
		return $query;
	}
151826
private function matchVariableRouteChunk($path, $variableRoutes)
    {
        $numGroups = 0;

        /** @var Route[] $routes */
        $routes   = [];
        $pattern   = '';
        foreach ($variableRoutes as $route) {
            $numVariables = $route->getParameterCount();
            $pattern .= '|' . $route->getRegexp();
            if ($numVariables < $numGroups && !isset($routes[ $numVariables ])) {
                $routes[ $numVariables ] = $route;
            } else {
                $numGroups = max($numGroups, $numVariables);
                $pattern .= str_repeat('()', $numGroups - $numVariables);
                $routes[ $numGroups++ ] = $route;
            }
        }
        if (!preg_match('#^(?' . $pattern . ')$#', $path, $matched)) {
            return false;
        }
        //Remove the whole match
        array_shift($matched);
        $route = $routes[ count($matched) ];

        $parameterNames = $route->getParameterNames();
        //get the elements of $matched that are actually parameters
        $parameters = array_intersect_key($matched, $parameterNames);
        $matchedParams = array_combine($parameterNames, $parameters);

        return new Match($route, $matchedParams);
    }
78632
public function toQuery( $variableSet, $factVariableBinding )
	{
		// return null;
		$variable = $this->variable['originalPrefix']
			? "{$this->variable['originalPrefix']}:{$this->variable['name']}"
			: $this->variable['name'];

		if ( $this->boundary == "start" ||  $this->boundary == "end" )
		{
			return "(xfi:period(.)[ if (xfi:is-instant-period(.) and xfi:is-start-end-period(xfi:period(\$$variable))) then (xfi:period-instant(.) eq xfi:period-{$this->boundary}(xfi:period(\$$variable))) else fn:false() ])";
		}
		else
		{
			return "fn:false()";
		}
	}
24201
public function matchUncoveredAspects( $variableSet, $uncoveredAspectFacts, $binding )
	{
		if ( ! $binding->valid() ) return true;
		if ( ! $variableSet->implicitFiltering || ! $uncoveredAspectFacts ) return true;

		// Make sure the facts in $uncoveredAspectFacts are consistent with the facts in $binding->uncoveredAspectFacts
		foreach ( $uncoveredAspectFacts as $aspect => $aspectFact )
		{
			if ( is_null( $aspectFact ) ) continue;
			if ( ! isset( $binding->uncoveredAspectFacts[ $aspect ] ) || is_null( $binding->uncoveredAspectFacts[ $aspect ] ) ) continue;

			if ( ! $this->lyquidityAspectMatch( $variableSet, $binding->uncoveredAspectFacts[ $aspect ], $aspectFact, $aspect) )
			{
				return false;
			}
		}

		return true;
	}
303317
private function evaluateAcceptanceRadius( $variableSet, $derivedValue, $fact, $factVars = array() )
	{
		if ( is_null( $this->radiusValue ) )
		{
			if ( ! is_null( $this->absoluteAcceptanceRadius ) || ! is_null( $this->proportionalAcceptanceRadius ) )
			{
				$expression = ! is_null( $this->absoluteAcceptanceRadius )
					? $this->absoluteAcceptanceRadius
					: $this->proportionalAcceptanceRadius;

				$expression = "$expression cast as xs:float";

				$vars = array_map( function( $param ) { return $param->result; }, $this->parameters );
				$vars = array_merge( $factVars, $vars );
				// $result = $this->evaluateXPath( $variableSet, $expression, $vars );
				$provider = new NodeProvider( $fact );

				$xpathExpression = XPath2Expression::Compile( $expression, $variableSet->nsMgr );

				$xpathExpression->AddToContext( "xbrlInstance", $variableSet->xbrlInstance );
				$xpathExpression->AddToContext( "xbrlTaxonomy", $variableSet->xbrlTaxonomy );
				$xpathExpression->AddToContext( "base", $variableSet->base );
				$result = $xpathExpression->EvaluateWithVars( $provider, $vars );

				$this->radiusValue = $result instanceof XPath2Item ? $result->getTypedValue() : $result;
			}
			else
			{
				$this->radiusValue = false;
			}
		}

		if ( ! is_null( $this->absoluteAcceptanceRadius ) )
		{
			return $this->radiusValue;
		}

		if ( ! is_null( $this->proportionalAcceptanceRadius ) )
		{
			return $this->radiusValue * $derivedValue;
		}

		return null;
	}
1160455
public function Filter( $facts, $variableSet )
	{
		// If the filter is being used in a boolean filter or there is a qname expresssion then return the input facts
		if ( $this->inBoolean || $this->qnameExpressions ) return $facts;

		$matched = array();
		$notMatched = array();

		foreach ( $facts as /** @var XPathNavigator $fact */ $fact )
		{
			if ( $this->testParent( $fact ) )
			{
				$matched[] = $fact->CloneInstance();
			}
			else
			{
				$notMatched[] = $fact->CloneInstance();
			}
		}

		return DocumentOrderNodeIterator::fromItemset( $this->complement ? $notMatched : $matched );
	}
783559
public function validate( $variableSet, $nsMgr )
	{
			try
		{
			if ( $this->scheme )
			{
				if ( ! $this->schemaXPath2Expression )
				{
					$this->schemaXPath2Expression = XPath2Expression::Compile( $this->scheme, $nsMgr );
				}
			}
		}
		catch ( \Exception $ex )
		{
			\XBRL_Log::getInstance()->formula_validation( "Specific scheme filter", "Failed to compile scheme expression",
				array(
					'schema expression' => $this->scheme,
					'error' => $ex instanceof XPath2Exception ? $ex->ErrorCode : get_class( $ex ),
					'reason' => $ex->getMessage()
				)
			);
			return false;
		}

		return parent::validate( $variableSet, $nsMgr );
	}
502558
public static Map<String, String> getXpathVariables(Map<String, Collection<AttributeBean>> attributeMap) {
        // Set all the bind variables in the query context

        Map<String, String> variables = new HashMap<String, String>();

        for (String t : targets) {
            int count = 0;
            for (AttributeBean bean : attributeMap.get(t.toLowerCase()
                                                       + "Attributes")) {
                if (bean.getId().equals(XACML_RESOURCE_ID)) {
                    variables.put("XacmlResourceId", bean.getId());

                    if (log.isDebugEnabled()) {
                        log.debug("XacmlResourceId = '" + bean.getId()
                                  + "'");
                    }


                    int c = 0;
                    for (String value : bean.getValues()) {
                        variables.put("XacmlResourceIdValue"
                                          + c, value);
                        if (log.isDebugEnabled()) {
                            log.debug("XacmlResourceIdValue"
                                      + c + " = '" + value + "'");
                        }


                        c++;
                    }
                } else {
                    variables.put(t + "Id" + count,
                                             bean.getId());

                    if (log.isDebugEnabled()) {
                        log.debug(t + "Id" + count + " = '" + bean.getId()
                                  + "'");
                    }

                    int valueCount = 0;
                    for (String value : bean.getValues()) {
                        variables.put(t + "Id" + count
                                                 + "-Value"
                                                 + valueCount,
                                                 value);
                        if (log.isDebugEnabled()) {
                            log.debug(t + "Id" + count + "-Value"
                                      + valueCount + " = '" + value + "'");
                        }

                        valueCount++;
                    }

                    count++;
                }
            }
        }
        return variables;


    }