* with * Foo * * This should be applied after control structures have been optimized */ class InlineInferredValues extends AbstractNormalization { /** * {@inheritdoc} */ protected $queries = ['//xsl:if', '//xsl:when']; /** * {@inheritdoc} */ protected function normalizeElement(DOMElement $element) { // Test whether the map has exactly one key and one value $map = XPathHelper::parseEqualityExpr($element->getAttribute('test')); if ($map === false || count($map) !== 1 || count($map[key($map)]) !== 1) { return; } $expr = key($map); $value = end($map[$expr]); $this->inlineInferredValue($element, $expr, $value); } /** * Replace the inferred value in given node and its descendants * * @param DOMNode $node Context node * @param string $expr XPath expression * @param string $value Inferred value * @return void */ protected function inlineInferredValue(DOMNode $node, $expr, $value) { // Get xsl:value-of descendants that match the condition $query = './/xsl:value-of[@select="' . $expr . '"]'; foreach ($this->xpath($query, $node) as $valueOf) { $this->replaceValueOf($valueOf, $value); } // Get all attributes from non-XSL elements that *could* match the condition $query = './/*[namespace-uri() != $XSL]/@*[contains(., "{' . $expr . '}")]'; foreach ($this->xpath($query, $node) as $attribute) { $this->replaceAttribute($attribute, $expr, $value); } } /** * Replace an expression with a literal value in given attribute * * @param DOMAttr $attribute * @param string $expr * @param string $value * @return void */ protected function replaceAttribute(DOMAttr $attribute, $expr, $value) { AVTHelper::replace( $attribute, function ($token) use ($expr, $value) { // Test whether this expression is the one we're looking for if ($token[0] === 'expression' && $token[1] === $expr) { // Replace the expression with the value (as a literal) $token = ['literal', $value]; } return $token; } ); } /** * Replace an xsl:value-of element with a literal value * * @param DOMElement $valueOf * @param string $value * @return void */ protected function replaceValueOf(DOMElement $valueOf, $value) { $valueOf->parentNode->replaceChild($this->createText($value), $valueOf); } }