Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to use PHP functions in XSLT templates? #23

Closed
tobyzerner opened this issue Dec 30, 2015 · 2 comments
Closed

Is it possible to use PHP functions in XSLT templates? #23

tobyzerner opened this issue Dec 30, 2015 · 2 comments

Comments

@tobyzerner
Copy link

Sorry, this is a support request, not an issue!

For example, if my template is:

<a href="{url}" class="UserMention">@<xsl:value-of select="@username"/></a>

Where I want {url} to be dynamically generated from a PHP function which is passed a couple of attributes, like:

function ($id, $username) use ($urlService) {
    return $urlService->generateUrlToUser($id, $username);
}
@JoshyPHP
Copy link
Member

Your (feature|support) requests are always welcome. 😀

There's a short and a long answer to this question. The short one goes like this: no, but you can have the next best thing by altering the XML before rendering:

$xml = '<r><p><USERMENTION id="1" username="admin">@admin</USERMENTION></p></r>';
echo "$xml\n", s9e\TextFormatter\Utils::replaceAttributes(
    $xml,
    'USERMENTION',
    function (array $attributes)
    {
        if (isset($attributes['id']))
        {
            $attributes['url'] = '/path/to/' . $attributes['id'];
        }

        return $attributes;
    }
);
<r><p><USERMENTION id="1" username="admin">@admin</USERMENTION></p></r>
<r><p><USERMENTION id="1" url="/path/to/1" username="admin">@admin</USERMENTION></p></r>

s9e\TextFormatter\Utils::replaceAttributes() can be used to replace the attributes of a given tag in the XML. The callback receives the old attributes and should return the new attributes. XML special chars are automatically handled but the new values are not validated; It's possible to return a string where a number should be so you have to remain as vigilant against XSS as you'd be with anything else.

In the example above, we target USERMENTION tags and add a url attribute to them. In your template, you'll be able to use something like <a href="{@url}">...</a> but you'll have to declare the url attribute or the template checker will complain that using unknown attributes as URLs is unsafe.

$tag->attributes->add('url')->filterChain->append('#url');

As for the long answer, it still sounds like "No, but..." except the second part is so vast it's still unclear to me. I've thought about allowing some PHP in templates but I've never found a solution that really satisfied me. ext/xsl has a registerPHPFunctions() method that enables PHP functions inside XPath expressions but it's relatively complicated and I've experienced some segfaults when using it in the past. Also, it wouldn't work in JavaScript.

I have considered ways to run callbacks in the renderer the same way callbacks are run in the parser, which would make it possible to maintain parity between PHP and JavaScript. I don't know what form it would take and I don't know whether it's worth implementing, that's why I'm waiting for use cases to emerge.

@tobyzerner
Copy link
Author

Thanks for the detailed response! The solution you provided in the short answer works perfectly. A way to run callbacks in the renderer would be great, but you're right, there doesn't seem to be any obvious way for it to work. And probably no need since using replaceAttributes works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants