$str)
{
if ($matches['MARK'][$i] === 'expression')
{
$tokens[] = ['expression', substr($str, 1, -1)];
}
else
{
$tokens[] = ['literal', strtr($str, ['{{' => '{', '}}' => '}'])];
}
}
return $tokens;
}
/**
* Replace the value of an attribute via the provided callback
*
* The callback will receive an array containing the type and value of each token in the AVT.
* Its return value should use the same format
*
* @param DOMAttr $attribute
* @param callable $callback
* @return void
*/
public static function replace(DOMAttr $attribute, callable $callback)
{
$tokens = self::parse($attribute->value);
foreach ($tokens as $k => $token)
{
$tokens[$k] = $callback($token);
}
$attribute->value = htmlspecialchars(self::serialize($tokens), ENT_NOQUOTES, 'UTF-8');
}
/**
* Serialize an array of AVT tokens back into an attribute value
*
* @param array $tokens
* @return string
*/
public static function serialize(array $tokens)
{
$attrValue = '';
foreach ($tokens as $token)
{
if ($token[0] === 'literal')
{
$attrValue .= preg_replace('([{}])', '$0$0', $token[1]);
}
elseif ($token[0] === 'expression')
{
$attrValue .= '{' . $token[1] . '}';
}
else
{
throw new RuntimeException('Unknown token type');
}
}
return $attrValue;
}
/**
* Transform given attribute value template into an XSL fragment
*
* @param string $attrValue
* @return string
*/
public static function toXSL($attrValue)
{
$xsl = '';
foreach (self::parse($attrValue) as list($type, $content))
{
if ($type === 'expression')
{
$xsl .= '';
}
elseif (trim($content) !== $content)
{
$xsl .= '' . htmlspecialchars($content, ENT_NOQUOTES, 'UTF-8') . '';
}
else
{
$xsl .= htmlspecialchars($content, ENT_NOQUOTES, 'UTF-8');
}
}
return $xsl;
}
}