PHP Conference Japan 2024

XSLTProcessor::registerPHPFunctions

(PHP 5 >= 5.0.4, PHP 7, PHP 8)

XSLTProcessor::registerPHPFunctions启用将 PHP 函数用作 XSLT 函数的能力

说明

public XSLTProcessor::registerPHPFunctions(array|string|null $functions = null): void

此方法启用将 PHP 函数用作 XSL 样式表中的 XSLT 函数的能力。

参数

functions

使用此参数可以仅允许从 XSLT 调用某些函数。

此参数可以是以下之一:一个 string(函数名)、一个函数名索引 array,或者一个关联 array,其中键是函数名,关联的值是 callable

返回值

没有返回值。

更新日志

版本 说明
8.4.0 现在,当使用 restrictarray 条目时,可以使用 callables 作为回调。

范例

示例 #1 从样式表简单调用 PHP 函数

<?php
$xml
= <<<EOB
<allusers>
<user>
<uid>bob</uid>
</user>
<user>
<uid>joe</uid>
</user>
</allusers>
EOB;
$xsl = <<<EOB
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="https://php.net/xsl">
<xsl:output method="html" encoding="utf-8" indent="yes"/>
<xsl:template match="allusers">
<html><body>
<h2>Users</h2>
<table>
<xsl:for-each select="user">
<tr><td>
<xsl:value-of
select="php:function('ucfirst',string(uid))"/>
</td></tr>
</xsl:for-each>
</table>
</body></html>
</xsl:template>
</xsl:stylesheet>
EOB;
$xmldoc = new DOMDocument();
$xmldoc->loadXML($xml);
$xsldoc = new DOMDocument();
$xsldoc->loadXML($xsl);

$proc = new XSLTProcessor();
$proc->registerPHPFunctions();
$proc->importStyleSheet($xsldoc);
echo
$proc->transformToXML($xmldoc);
?>

参见

添加注释

用户贡献的注释 20 条

up
3
heinemann 点 juergen 在 hjcms 点 de
18 年前
你可以在 PHP 源码 php-5.*/ext/xsl/tests 中找到更多示例
<?php

$xform
= <<<EOT
<?xml version = '1.0' encoding = 'utf-8' ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="https://php.net/xsl"
xsl:extension-element-prefixes="php"
>
<xsl:output method="xml" indent="yes" encoding="utf-8" />
<xsl:namespace-alias stylesheet-prefix="php" result-prefix="xsl" />
<xsl:template match="root">
<html>
<head>
<title>日期格式</title>
</head>
<body>
<xsl:for-each select="datenode">
<li>
<xsl:value-of select="php:functionString('convertDate', . )" />
</li>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
EOT;

function
convertDate( $i )
{
setlocale( LC_TIME, 'de_DE' );
return
utf8_encode( strftime( '%B %d %A %Y %H:%M:%S CET', $i ) );
}

$xsl = new XSLTProcessor;
$xsl->registerPHPFunctions();
$xsl->setParameter( 'DOCTYPE', 'PUBLIC', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' );
$xsl->setParameter( 'html', 'xmlns', 'http://www.w3.org/1999/xhtml' );

$xdom = new DomDocument( '1.0', 'utf-8' );
$xdom->loadXML( $xform );

$xsl->importStyleSheet( $xdom );
unset(
$xdom );

$dom = new DomDocument( '1.0', 'utf-8' );
$r = $dom->appendChild( $dom->createElement( 'root' ) );
foreach (
range( 1, 12 ) AS $i ) {
$r->appendChild( $dom->createElement( 'datenode', mktime( date('G'), date('i'), date('s'), $i, date('d'), date('Y') ) ) );
}

header( "Content-Type: text/html; charset=utf-8;" );
header( "Content-Encoding: utf-8" );
echo
$xsl->transformToXML( $dom );

?>
up
2
Matthew, info at mathias-schaefer dot de
14 年前
=> 不需要你的类的实例,你必须注意命名空间(使用 5.3 版本)。

<!-- xsl -->
<xsl:value-of select="php:function ('My\Name\Space\MyClassName::methodName',1+2)"/>
--->

<?php
namespace My\Name\Space;

class
MyClassName
{
static public function
methodName($someArgument)
{
return
"结果是:".$someArgument;
}
}
?>

<!-- 结果 -->
结果是:3
-->

=> 不需要对参数进行字符串转换
=> 返回数字也是可能的(也许也可以返回 DOM 节点)

继续编码吧
up
1
Demerit
14 年前
各位,让我们把术语弄正确。

如果你要调用一个位于类中的函数,请使用它的实例名引用它,而不是它的类名。

class.my_class.php

<?php
class class_name {
static function
function_name($in){
return (
$out);
}
}
?>

calling_document.php

<?php
require_once('class.my_class.php');
$instance_name=new class_name();
?>

my_xslt.xsl

<xsl:value-of select="php:function ('instance_name::function_name','garbage')" />

顺便说一下,在 5.1.6 版本中,双冒号 (::) 是调用位于类中的函数时唯一有效的方法。但是,你必须将你的函数声明为静态的。像一些人建议的那样使用 ->(例如,php:function ('instance_name->function_name','garbage'))根本不起作用,无论你如何声明你的函数。
up
2
taylorbarstow 在那个谷歌邮箱
18 年前
对我之前关于从 PHP 函数返回节点集到 XSLT 的说明(如下)的补充

你不必返回 DOMDocument,DOMElement 也可以。此外,返回 DOMElement 可以解决我下面讨论的以及“Ingram”也提到的丢弃根节点的问题。
up
2
Ingram
18 年前
在测试由以下人员贡献的节点集返回时

taylorbarstow 在那个谷歌邮箱

(效果非常好,谢谢!)

我发现使用

===
“想必,创建一个模板来丢弃根节点是值得的

<xsl:template select="*" mode="discardRoot">
<xsl:apply-templates select="./*" />
</xsl:template>

你可以像这样调用它

<xsl:apply-templates select="php:function('getNodeSet')" mode="discardRoot" /> "
===

我只能输出文本,而不能输出应用模板后的任何标签 - 即它剥离了文本周围的所有元素。

相反,使用

===
<xsl:template match="/">
<xsl:for-each select="php:function('getNodeSet')" />
<xsl:apply-templates />
</xsl:for-each>
</xsl:template>

这有效地丢弃了根节点。
===

工作正常,并允许我对返回的节点集应用模板而没有问题。
up
2
hopeseekr at gmail dot com
18 年前
我遇到的最麻烦的事情之一是编码 URL 参数。我的意思是,假设你想用“search+terms”而不是“search terms”填充链接。我在 XML 中包含两个单独的 URL,这太荒谬了。

下面是一个更优雅的 PHP+XSLT 解决方案。你还会看到它使用了 registerPHPFunctions() 的两个*未记录*的功能,即 php:functionString() 和将参数传递给函数。我是通过反复试验才弄明白的;我真的希望这个说明能帮助你,因为它*大大*扩展了 XSLT 中 php 函数的功能!

<?php
/* --- XML 输入 --- */
<search_results>
<
query>演唱会门票</query>
</
search_results>

/* --- XSL 代码 --- */
<!-- 显示查询 -->
<
xsl:template match="search_results">
<!--
通过 PHP 获取 URL 编码的字符串 -->
<
xsl:variable name="safeurl" as="xs:string" select="php:functionString('urlencode', query)" />
<
p>您对 <em><xsl:value-of select="query"/></em> 的搜索可以在 <a href="http://www.tixtix.com/search.php?q={$safeurl}">我们的搜索引擎</a> 继续</p>
</
xsl:template>

/* --- XHTML 输出 --- */
<p>您对 <em>演唱会门票</em> 的搜索可以在 <a href="http://www.tixtix.com/search.php?q=space+cowboy">我们的搜索引擎</a> 继续</p>
?>

很酷,对吧?
up
2
taylorbarstow 在那个谷歌邮箱
19 年前
从 PHP 函数,你可以使用 DOMDocument 将节点集传递回 XSL。例如

<?php

function getNodeSet() {
$xml =
"<test>" .
"<a-node>这是一个节点</a-node>" .
"<a-node>这是另一个节点</a-node>" .
"</test>";
$doc = new DOMDocument;
$doc->loadXml($xml);
return
$doc;
}

?>

我发现的唯一问题是,返回的 DOM 文档中的根级节点就像原始文档的根级节点一样。因此,很容易引入像这样的无限循环:

<xsl:template match="/">
<xsl:apply-templates select="php:function('getNodeSet')" />
</xsl:template>

为了避免这种情况,我一直使用像这样的构造:

<xsl:template match="/">
<xsl:for-each select="php:function('getNodeSet')" />
<xsl:apply-templates />
</xsl:for-each>
</xsl:template>

这可以有效地丢弃根节点。大概,值得创建一个模板来执行丢弃操作:

<xsl:template select="*" mode="discardRoot">
<xsl:apply-templates select="./*" />
</xsl:template>

你可以像这样调用它

<xsl:apply-templates select="php:function('getNodeSet')" mode="discardRoot" />
up
2
zac at zacbowling dot com
20 年前
如果人们在使用此函数时遇到问题,我经常告诉他们的一件事是检查
某些类型的流行软件生成并添加到您的 xml 页面中的任何“xmlns”属性。
某些类型的流行软件生成并添加到您的 xml 页面中的任何“xmlns”属性。
某些类型的流行软件生成并添加到您的 xml 页面中的任何“xmlns”属性。

<?php
$file
= "http://data.map***.net/m***ck.asmx/GetMessages?IMEI=$id";

$docxml = file_get_contents($file);

//您可能需要执行类似这样的操作,其中
//我删除了由我的 ASP.NET SOAP 响应返回的任何 xmlns 标记实例。

$docxml =
str_replace("xmlns=\"http://data.map***.net/m***ck.asmx?WSDL\"",
"",$docxml);

$xslt = new xsltProcessor;

//如果不删除它们,则此函数将失败。
$xslt->registerPHPFunctions();
$xslt->importStyleSheet(DomDocument::load('../xsl/message.xsl'));
print
$xslt->transformToXML(DomDocument::loadXML($docxml));

?>

此外,此函数还有一些很酷的技巧,您可以调用
内置的 PHP 函数。例如:

<xsl:value-of
select="php:function('nl2br',string(MessageContent/Message))"
disable-output-escaping="yes"/>

该 XSL 值现在将返回您的正常字符串,但会将
xml 中的所有换行符替换为“<br />”。

另请注意“disable-output-escaping="yes"”语句。如果
您不调用此函数,则该绑定的输出将基本上通过
“htmlencode()”类型的函数运行。

最后但同样重要的是,请查看我在
传递回 XSL 之前调用的“string()”函数。这是因为如果不
调用它,它将在运行时尝试传递节点对象,
而不是其值(这很可能是您唯一想要的)。

这个函数非常棒,可以引发一些非常
有趣的代码开发。可以远程加载皮肤。
您可以用 PHP 编写一个 RSS 阅读器,而无需太多
代码。您可以将 XHTML 页面解析为另一个视图(无论是
本地还是远程)。然后,您可以使用相同的 XML
内容并将其用于 ASP.NET、Java 甚至是
命令行处理工具,使用完全相同的 XSL
样式表并为您生成页面的前端,而无需
太多更改。我非常兴奋。

编码愉快。
up
2
zac at zacbowling dot com
20 年前
关于此函数需要注意的一件事。在将许多值传递给函数之前,需要使用 XLS 中的“string()”函数将其转换为 XSLT 字符串,并且当您返回它们时,请确保如果它们是字符串,则在执行此操作之前在 php 中调用“strval()”。这为我节省了数小时。

希望对您有所帮助。

Zac Bowling
up
1
Ariz Jacinto
16 年前
如果您想使用类似于 XPath 2.0[1] 的 replace() 函数,并且您想避免使用类似于此[2] 的长 XSLT 函数,则可以使用 PHP 的 str_replace() 代替

<xsl:value-of select="php:functionString('str_replace','pattern', 'replacement' , . )">

链接
[1] http://www.w3.org/TR/2004/WD-xpath-functions-20041029/#func-replace
[2] http://aspn.activestate.com/ASPN/Cookbook/XSLT/Recipe/65426

_
up
1
thsoft at vipmail dot hu
16 年前
不幸的是,您不能将数组从 XLST 传递到 PHP。
但是您可以将任意数量的参数传递给 PHP 函数,然后使用 func_get_args() 将它们作为数组获取。
[编写与 array() 构造相同的函数没有意义,因为函数的返回值在作为参数传递给另一个函数时会被转换为字符串。这意味着无法以这种方式处理深层数组。]
up
1
junkmail at eighteyes dot com
20 年前
编写使用回调函数的样式表时,请务必包含 php 的命名空间声明,如下所示:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="https://php.net/xsl" version='1.0'>
up
1
begemot at php dot com dot ua
20 年前
我想它对您有帮助。
<?php

function dateLang () {
return
strftime("%A");
}

$xsl = new DomDocument();
$xsl->load("datetime.xsl");
$inputdom = new DomDocument();
$inputdom->load("today.xml");

$proc = new XsltProcessor();
$proc->registerPhpFunctions();

// 加载文档并使用 $xslt 处理
$xsl = $proc->importStylesheet($xsl);

/* 转换并输出 xml 文档 */
$newdom = $proc->transformToDoc($inputdom);

print
$newdom->saveXML();

?>

这是将调用该函数的 XSLT 样式表 datetime.xsl:

<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="https://php.net/xsl">
<xsl:template match="/">
<xsl:value-of select="php:function('dateLang')" />
</xsl:template>
</xsl:stylesheet>

这是一个绝对最小的 XML 文件 today.xml,用于通过样式表传递(尽管 articles.xml 将实现相同的结果):

<?xml version="1.0" encoding="iso-8859-1" ?>
<today></today>
up
0
Nic Luciano
15 年前
Ritch 说“如果您希望使用类内部的函数,请使用双冒号 (::) 表示法...”

另请注意,类函数必须声明为静态。
up
0
thsoft at vipmail dot hu
17 年前
接收从 PHP 返回的 DOM 节点(无论是元素、文档、文档片段等)的正确方法是使用 <xsl:copy-of select="php:function...

我在这里找到了这个想法和一个示例:http://bugs.php.net/bug.php?id=29409

有关原因的技术细节,请参阅 http://www.w3.org/TR/xslt#copy-of
up
0
phil at worldpoolfederation dot com
18 年前
不正确

使用 :: 调用静态函数
使用 -> 调用非静态函数

您必须在 php 5.1 中将函数定义为静态才能静态调用它。
up
0
mark at thirst dot org
18 年前
Ritch 说“如果您希望使用类内部的函数,请使用双冒号 (::) 表示法...”这在 5.0.4 中有效,但在 5.1.6 中不再有效。
up
0
franp at free dot fr
18 年前
请注意,如果您希望您的输出针对某些 xhtml dtd 进行验证,则必须将以下属性添加到 xslt 样式表的 xsl:stylesheet 元素中:
exclude-result-prefixes="php"。

否则,您会收到“无效属性 xmlns:php”错误。
up
0
benbarnett
19 年前
您可以在 XSL 中使用 php:functionString(),它将自动将输出转换为字符串!
up
-1
Ritch at Bugsoftware dot co dot uk
19 年前
如果您希望使用类内部的函数,请使用双冒号 (::) 表示法,例如:

php:functionString('classname::function')

该函数作为静态函数触发,因此其行为类似于全局命名空间中的函数。
To Top