PHP Conference Japan 2024

xml_set_character_data_handler

(PHP 4, PHP 5, PHP 7, PHP 8)

xml_set_character_data_handler设置字符数据处理器

描述

xml_set_character_data_handler(XMLParser $parser, callable|string|null $handler): true

为XML解析器parser设置字符数据处理函数。

参数

parser

XML 解析器。

handler

如果传递null,则处理器将重置为其默认状态。

警告

空字符串也会重置处理器,但是从PHP 8.4.0开始已弃用。

如果handler是一个callable,则该callable将被设置为处理器。

如果handler是一个string,它可以是使用xml_set_object()设置的对象的方法名称。

警告

从PHP 8.4.0开始已弃用。

警告

从PHP 8.4.0开始,在设置处理器时会检查callable是否有效,而不是在调用时检查。这意味着必须在将方法字符串设置为回调之前调用xml_set_object()。但是,由于此行为从PHP 8.4.0开始也已弃用,因此建议改为使用正确的callable作为方法。

处理器的签名必须为

handler(XMLParser $parser, string $data): void
parser
调用处理器的XML解析器。
data
作为字符串的字符数据。

对于XML文档中的每一部分文本,都会调用字符数据处理器。它可以在每个片段内多次调用(例如,对于非ASCII字符串)。

返回值

始终返回true

变更日志

版本 描述
8.4.0 将非callable string 传递给handler现在已弃用,请对方法使用正确的callable,或使用null重置处理器。
8.4.0 现在在设置处理器时检查handler作为callable的有效性,而不是在调用时检查。
8.0.0 parser现在期望一个XMLParser 实例;以前,期望一个有效的xml resource
添加注释

用户贡献注释 9 条注释

flobee
19 年前
关于 Philippe Marc 和 karuna_gadde 的示例

我发现 xml_set_character_data_handler 回调函数可能会对同一个元素多次调用,特别是内容很短时(在 Windows 上发生)。

所以检查一下可以给你答案,可能对于长字符串也是如此。
例如
<?php
xml_set_character_data_handler
($this->parser, "cdata");
//...
function cdata($parser, $cdata) {
// ...
if(isset($this->data[$this->currentItem][$this->currentField])) {
$this->data[$this->currentItem][$this->currentField] .= $cdata;
} else {
$this->data[$this->currentItem][$this->currentField] = $cdata;
}
?>
jhill at live dot com
16 年前
为了检测数据是否正在连接,您可以跟踪上一个函数调用是否是数据处理函数。
例如,使用下面的 $this->inside_data 变量

<?php
xml_set_element_handler
($this->parser, "start_tag", "end_tag");
xml_set_character_data_handler($this->parser, "contents");

protected function
contents($parser, $data)
{
switch (
$this->current_tag) {
case
"name":
if (
$this->inside_data)
$this->name .= $data; // 需要连接数据
else
$this->name = $data;
break;
...
}
$this->inside_data = true;
}

protected function
start_tag($parser, $name)
{
$this->current_tag = $name;
$this->inside_data = false;
}

protected function
end_tag() {
$this->current_tag = '';
$this->inside_data = false;
}
?>
ben at removethis emediastudios dotcom
19 年前
我也很喜欢未公开的“分割”功能 :-p。

我建议不要根据当前标签名称是否与之前的标签名称发生变化来连接数据,而是像下面这样始终进行连接,并在endElement函数中取消设置$catData变量。

<?php

function endElement ($parser, $data) {
global
$catData;

// 因为我们处于元素结束位置,所以知道任何分割都已完成
unset($GLOBALS['catData']);
}

function
characterData ($parser, $data) {
global
$catData;

// 如果正在进行分割,则连接数据
$catData.=$data;

}

?>

这帮助我解决了以下类似数据的问题,由于空标签未调用characterData,即使没有进行分割,之前的和当前标签名称也相同。

<companydept>
<companydeptID></companydeptID>
<companyID>1</companyID>
<companydeptName></companydeptName>
</companydept>
<companydept>
<companydeptID></companydeptID>
<companyID>2</companyID>
<companydeptName></companydeptName>
</companydept>
<companydept>
<companydeptID></companydeptID>
<companyID>3</companyID>
<companydeptName></companydeptName>
</companydept>
unspammable-iain at iaindooley dot com
18年前
关于:下面jason at omegavortex dot com,处理空格问题的另一种方法是

function charData($parser,$data)
{
$char_data = trim($data);

if($char_data)
$char_data = preg_replace('/ */',' ',$data);

$this->cdata .= $char_data;
}

这意味着

<p>这里是我的文本 <a href="something">我的文本</a>
这里还有一些文本,行首有一些空格
beginning of the line</p>

输出正确。如果要处理文件中的制表符,可以进行进一步替换。我只使用空格。如果只使用trim(),则会丢失上面<a>标签之前的空格,但trim()是检查完全为空的字符数据的好方法,然后只需将多个空格替换为单个空格即可。这将保留cdata开头和结尾的单个空格。
yaroukh at email dot cz
19 年前
如果有人能完成此函数的文档说明就好了。我认为应该(至少)在文档中提及“分割”行为,如果没有解释的话(请!)。我不确定切割是否发生在每1024字节/字符数据之后。

我的经验如下
[xmlFile]
...
<label>slo|?ka</label>
<comment>koment|?&#345; slo?ky</comment>
...
[/xmlFile]
(字符数据被分割的地方用管道标记。此外,还有带变音符号的小写拉丁字母“r”代替&#345;。)

由于文档中没有提到分割,因此可以认为这是一个错误;尤其是在使用UTF-8并且切割发生在某些特殊字符之前时。
(是否应该将$cData的连接视为处理字符数据的正确和最终方法?)

我还建议在fc具有替代用法时在“描述”中添加另一行(而不是将其隐藏在“注意”中:o);在这种特定情况下,我更喜欢这样

描述
bool xml_set_character_data_handler ( resource parser, callback handler )
bool xml_set_character_data_handler ( resource parser, object reference, method name )

……当然还有数十个函数的文档是这样工作的(我的意思是,没有在“描述”部分提及替代用法)。

祝您有美好的一天
Yaroukh
Philippe Marc
20年前
如何覆盖xml_set_character_data_handler的1024个字符限制。
我花了一些时间才找到解决方法!

调用基本XML解析器时
$parseurXML = xml_parser_create();
xml_set_element_handler($parseurXML, "opentagfunction", "closetagfunction");
xml_set_character_data_handler($parseurXML, "textfunction");

textfunction一次只接收1024个字符,即使文本长达4000个字符。事实上,解析器似乎将数据分成1024个字符的块。处理方法是将它们连接起来。

示例
如果您有一个名为UNIPROT_ABSTRACT的XML标签,其中包含4000个字符的蛋白质描述
function textfunction($parser, $text)
{
if ($last_tag_read=='UNIPROT_ABSTRACT') $uniprot.=$text;
}
该函数被调用4次,并接收1024+1024+1024+928个字符,这些字符将使用“.=”连接函数连接到$uniprot变量中。

很容易做到,但没有文档说明!
Brad dot Harrison at griffith dot edu dot au
20年前
如果您需要修剪HTML代码的空格,并且不依赖空格来格式化文本(如果您依赖空格,那么就该使用样式表了),那么这段代码将非常有用。

$data=eregi_replace(">"."[[:space:]]+"."<","><",$data);
$data=eregi_replace(">"."[[:space:]]+",">",$data);
$data=eregi_replace("[[:space:]]+"."<","<",$data);
dan30odd08 at hotmail dot com
21年前
我只想提一下,在使用字符数据处理程序解析XML文件时,我遇到了一个问题。如果您碰巧在XML数据文件中存储了一个字符串,该字符串也是一个内部PHP函数,并且您想将其作为字符串输出,则解析器似乎无法识别它。
我找到了一种解决此问题的方法。在我的例子中,我用值read存储了一个字符串。这将不允许我输出数据,因此为了解决这个问题,我在数据元素中的每个字符前都添加了一个反斜杠。

例如 <xml>
从 <element>read</element>
到 <element>////read</element>

我不知道是否有人遇到过这个问题,但我认为我只是把它放在这里,以防万一有人被卡住了。
ken at positive-edge dot com
22年前
当解析器解析字符数据时,函数处理程序会被多次调用。它不会像建议的那样返回整个字符串。有一些特殊情况总是会强制解析器停止扫描并调用字符数据处理程序。这种情况发生在

- 解析器遇到实体声明,例如&amp; (&) 或&apos; (?)
- 解析器完成实体解析
- 解析器遇到换行符 (\n)
- 解析器遇到一系列制表符 (\t)

也许还有其他情况。

例如,如果我们有以下xml内容

<mytag name=?Ken Egervari? title=?Chief Technology Officer?>
Ken has been Positive Edge&apos;s Chief Technology Officer for 2 years.
</mytag>

解析器将调用字符数据处理程序6次。将会发生以下情况

1 \n
2 \t
3 Ken has been Positive Edge
4 ?
5 s Chief Technology Officer for 2 years.
6 \n

希望这对大家有帮助。
To Top