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,則將該可呼叫項目設定為處理器。

如果 handler 是一個 string,它可以是使用 xml_set_object() 設定的物件的方法名稱。

警告

從 PHP 8.4.0 開始已棄用。

警告

從 PHP 8.4.0 開始,可呼叫項目會在設定處理器時檢查是否有效,而不是在呼叫時檢查。這表示必須先呼叫 xml_set_object(),才能將方法字串設定為回呼。但是,由於此行為也從 PHP 8.4.0 開始已棄用,因此建議改用適當的 callable 來處理方法。

處理器的簽名必須是

handler(XMLParser $parser, string $data): void
parser
呼叫處理器的 XML 解析器。
data
字元資料,以字串形式表示。

會為 XML 文件中的每個文字片段呼叫字元資料處理器。它可以在每個片段內多次呼叫(例如,對於非 ASCII 字串)。

傳回值

總是傳回 true

變更記錄

版本 描述
8.4.0 將非 callablestring 傳遞給 handler 現在已棄用,請針對方法使用適當的可呼叫項目,或使用 null 重置處理器。
8.4.0 現在會在設定處理器時檢查 handler 作為 callable 的有效性,而不是在呼叫時檢查。
8.0.0 parser 現在預期是 XMLParser 執行個體;先前,預期是有效的 xml resource
新增註解

使用者貢獻的註解 9 個註解

2
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;
}
?>
2
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; // need to concatenate 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;
}
?>
1
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>
1
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>
這是一些更多文字,在行的開頭有一些空格之後</p>
在行的開頭有一些空格之後</p>

可以正確顯示。如果您想要處理檔案中的 Tab 字元,可以進行更多取代。我只使用空格。如果您只使用 trim(),則會遺失上面 <a> 標籤前的空格,但 trim() 是檢查完全空白的字元資料的好方法,然後只需將多個空格取代為單個空格。這會保留 cdata 開頭和結尾的單個空格。
1
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
1
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");

即使文字長度為 4000 個字元,textfunction 一次也只接收 1024 個字元。事實上,剖析器似乎將資料分割成 1024 個字元的片段。處理這個問題的方法是將它們連接起來。

範例
如果您有一個名為 UNIPROT_ABSTRACT 的 XML 標籤,其中包含 4000 個字元的蛋白質描述
function textfunction($parser, $text)
{
if ($last_tag_read=='UNIPROT_ABSTRACT') $uniprot.=$text;
}
該函式會被呼叫 4 次,並接收 1024+1024+1024+928 個字元,這些字元將使用 ".=" 連接函式連接到 $uniprot 變數中。

很容易做到,但沒有文件說明!
1
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);
1
dan30odd08 at hotmail dot com
21 年前
我只想提到,在使用字元資料處理程式剖析 XML 檔案時,我遇到了一個問題。如果您剛好有一個字串,該字串也是儲存在您的 XML 資料檔案中的內部 PHP 函式,並且您想要將其輸出為字串,則剖析器似乎無法辨識它。
我找到了一種解決這個問題的方法。在我的情況下,我儲存了一個值為 read 的字串。這不允許我輸出資料,因此為了解決這個問題,我為資料元素中的每個字元新增了一個反斜線。

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

我不知道是否有人遇到過這個問題,但我認為我應該把它放在這裡,以防有人被這個問題困住。
1
ken at positive-edge dot com
22 年前
當它剖析字元資料時,會多次呼叫函式處理程式。它不會像它暗示的那樣傳回整個字串。有一些特殊例外情況總是會強制剖析器停止掃描並呼叫字元資料處理程式。當發生以下情況時

- 剖析器遇到實體宣告,例如 &amp; (&) 或 &apos; (?)
- 剖析器完成剖析實體
- 剖析器遇到換行符號 (\n)
- 剖析器遇到一系列 Tab 字元 (\t)

也許還有其他情況。

例如,如果我們有以下 XML 內容

<mytag name=?Ken Egervari? title=?Chief Technology Officer?>
Ken 擔任 Positive Edge 的技術長 2 年了。
</mytag>

剖析器會呼叫字元資料處理程式 6 次。這就是將會發生的事情

1 \n
2 \t
3 Ken 擔任 Positive Edge
4 ?
5 s 技術長 2 年了。
6 \n

我希望這對人們有幫助。
To Top