我費了好一番功夫才找到相關文件,因此將它發佈在此,希望能幫助到其他人。
如果您想使用多個 libxml 選項,請使用管道符號分隔它們,如下所示:
<?php
$xml = simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
?>
(PHP 5, PHP 7, PHP 8)
simplexml_load_string — 將 XML 字串解譯為物件
$data
,$class_name
= SimpleXMLElement::class,$options
= 0,$namespace_or_prefix
= "",$is_prefix
= false
接受格式良好的 XML 字串並將其作為物件返回。
data
格式良好的 XML 字串
類別名稱
您可以使用這個選用參數,以便 simplexml_load_string() 會返回指定類別的物件。該類別應繼承 SimpleXMLElement 類別。
選項
位元 OR
的 libxml 選項常數。
命名空間或前綴
命名空間前綴或 URI。
是否為前綴
如果 namespace_or_prefix
是前綴,則為 true
;如果是 URI,則為 false
;預設為 false
。
返回一個 物件,其類別為 SimpleXMLElement,其屬性包含 XML 文件中的數據,或者在失敗時返回 false
。
針對 XML 資料中找到的每個錯誤,都會產生 E_WARNING
錯誤訊息。
使用 libxml_use_internal_errors() 來抑制所有 XML 錯誤,並使用 libxml_get_errors() 之後迭代它們。
範例 #1 解析 XML 字串
<?php
$string = <<<XML
<?xml version='1.0'?>
<document>
<title>四十個什麼?</title>
<from>Joe</from>
<to>Jane</to>
<body>
我知道那是答案 -- 但問題是什麼?
</body>
</document>
XML;
$xml = simplexml_load_string($string);
print_r($xml);
?>
上述範例將輸出
SimpleXMLElement Object ( [title] => Forty What? [from] => Joe [to] => Jane [body] => I know that's the answer -- but what's the question? )
此時,您可以使用 $xml->body
等等。
我費了好一番功夫才找到相關文件,因此將它發佈在此,希望能幫助到其他人。
如果您想使用多個 libxml 選項,請使用管道符號分隔它們,如下所示:
<?php
$xml = simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
?>
將結果轉換為陣列的更簡單方法(需要 json 模組)。
<?php
function object2array($object) { return @json_decode(@json_encode($object),1); }
?>
範例
<?php
$xml_object=simplexml_load_string('<SOME XML DATA');
$xml_array=object2array($xml_object);
?>
檢查剖析錯誤時要小心。空的 SimpleXMLElement 可能會解析為 FALSE,如果您的 XML 不包含任何文字或只包含命名空間元素,您的錯誤檢查可能是錯誤的。檢查剖析錯誤時,請務必使用 `=== FALSE`。
<?php
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Root xmlns:ns1="http://example.com/custom">
<ns1:Node>這裡有一些內容</ns1:Node>
</ns1:Root>
XML;
$simplexml = simplexml_load_string($xml);
// 這會印出「剖析錯誤」。
echo ($simplexml ? '有效的 XML' : '剖析錯誤'), PHP_EOL;
// 但這會印出「這裡有一些內容」,證明
// SimpleXML 物件已成功建立。
echo $simplexml->children('http://example.com/custom')->Node, PHP_EOL;
// 請改用以下方式:
echo ($simplexml !== FALSE ? '有效的 XML' : '剖析錯誤'), PHP_EOL;
?>
參見
https://bugs.php.net/bug.php?id=31045
https://bugs.php.net/bug.php?id=30972
https://bugs.php.net/bug.php?id=69596
似乎有很多關於 SimpleXML 處理 CDATA 的「問題」的討論,以及撰寫用於移除 CDATA 的函數等等。一開始我也這麼認為,但它在 PHP 5.2.6 下的表現其實很好。
關鍵在上面範例 #6 中有提到
http://uk2.php.net/manual/en/simplexml.examples.php
「要將元素或屬性與字串比較,或將其傳遞給需要字串的函式,您必須使用 (string) 將其強制轉換為字串。否則,PHP 會將元素視為物件。」
如果標籤包含 CDATA,SimpleXML 會記住這個事實,方法是將其與元素的字串內容分開表示。因此,某些函式,包括 print_r(),可能不會顯示您預期的結果。但如果您明確地強制轉換為字串,您將獲得完整內容。
<?php
$xml = simplexml_load_string('<foo>Text1 & XML entities</foo>');
print_r($xml);
/*
SimpleXMLElement 物件
(
[0] => Text1 & XML 實體
)
*/
$xml2 = simplexml_load_string('<foo><![CDATA[Text2 & raw data]]></foo>');
print_r($xml2);
/*
SimpleXMLElement 物件
(
)
*/
// 我的 CDATA 在哪裡?
// 讓我們嘗試顯式轉換
print_r( (string)$xml );
print_r( (string)$xml2 );
/*
Text1 & XML 實體
Text2 & 原始資料
*/
// 好多了
?>
如同前面所述,不要使用 var_dump() 或 print_r() 來查看 SimpleXML 物件結構,因為它們的回傳結果並非總是您預期的。
考慮以下情況
<?php
// xml 中的資料
$xml_txt = '
<root>
<folder ID="65" active="1" permission="1"><![CDATA[aaaa]]></folder>
<folder ID="65" active="1" permission="1"><![CDATA[bbbb]]></folder>
</root>';
// 將 xml 載入到 SimpleXML 物件中
$xml = simplexml_load_string($xml_txt, 'SimpleXMLElement', LIBXML_NOCDATA);//LIBXML_NOCDATA LIBXML_NOWARNING
// 查看物件結構
print_r($xml);
/* 輸出
SimpleXMLElement 物件
(
[folder] => 陣列
(
[0] => aaaa
[1] => bbbb
)
)
*/
// 但是...
foreach ($xml->folder as $value){
print_r($value);
}
/* 輸出每個 folder 元素的完整結構:
SimpleXMLElement 物件
(
[@attributes] => 陣列
(
[ID] => 65
[active] => 1
[permission] => 1
)
[0] => aaaa
)
SimpleXMLElement 物件
(
[@attributes] => 陣列
(
[ID] => 65
[active] => 1
[permission] => 1
)
[0] => bbbb
)
*/
?>
這似乎沒有在任何地方被記錄,但是您可以參考元素的「值」來更改它,如下所示
<?php
$xml = simplexml_load_string('<root><number>1</number></root>');
echo $xml->asXml(). "\n\n";
$xml->number->{0} = $xml->number->{0} + 1;
echo $xml->asXml();
?>
會印出
<?xml version="1.0"?>
<root><number>1</number></root>
<?xml version="1.0"?>
<root><number>2</number></root>
然而,這只適用於直接賦值,不適用於其他運算符。
<?php
$xml = simplexml_load_string('<root><number>1</number></root>');
echo $xml->asXml(). "\n\n";
$xml->number->{0} += 1;
// 或:
$xml->number->{0}++;
echo $xml->asXml();
?>
以上兩種情況都會導致
<?xml version="1.0"?>
<root><number>1</number></root>
<?xml version="1.0"?>
<root><number>1<0/></number></root>
請注意,並非所有 LIBXML 選項都支援 options 參數。
例如,LIBXML_XINCLUDE 無法使用。 但是有一個解決方法
<?php
$xml = new DOMDocument();
$xml->loadXML ($XMLString);
$xml->xinclude();
$xml = simplexml_import_dom($xml);
?>
當序列化包含 HTML CDATA 的欄位時,以下的解決方法會出現問題。 對於 HTML 以外的任何其他內容類型,請嘗試修改 parseCDATA 函數。
序列化之前只需添加這些行。
這也是這個錯誤的解決方法 http://bugs.php.net/bug.php?id=42001
<?PHP
if(strpos($content, '<![CDATA[')) {
function parseCDATA($data) {
return htmlentities($data[1]);
}
$content = preg_replace_callback(
'#<!\[CDATA\[(.*)\]\]>#',
'parseCDATA',
str_replace("\n", " ", $content)
);
}
?>
一個簡單的擴展,添加了一個用於檢索特定屬性的方法
<?php
class simple_xml_extended extends SimpleXMLElement
{
public function Attribute($name)
{
foreach($this->attributes() as $key=>$val)
{
if($key == $name)
return (string)$val;
}
}
}
$xml = simplexml_load_string('
<xml>
<dog type="poodle" owner="Mrs Smith">Rover</dog>
</xml>', 'simple_xml_extended');
echo $xml->dog->Attribute('type');
?>
輸出 'poodle'
我比較喜歡用這種技巧,而不是將屬性進行類型轉換。
我想要將一個包含字串和其他相同類型陣列的陣列轉換成一個 simplexml 物件。
以下是我開發用於執行此轉換的函式 array2xml 的程式碼。請注意,這段程式碼很簡單,沒有任何檢查。
<?php
函數 array2xml($array, $tag) {
函數 ia2xml($array) {
$xml="";
foreach ($array as $key=>$value) {
if (is_array($value)) {
$xml.="<$key>".ia2xml($value)."</$key>";
} else {
$xml.="<$key>".$value."</$key>";
}
}
return $xml;
}
return simplexml_load_string("<$tag>".ia2xml($array)."</$tag>");
}
$test['type']='lunch';
$test['time']='12:30';
$test['menu']=array('entree'=>'salad', 'maincourse'=>'steak');
echo array2xml($test,"meal")->asXML();
?>
這是我的簡易 SimpleXML 包裝函式。
據我所知,它的功能和 Julio Cesar Oliveira 的(上面)一樣。
它會將 XML 字串解析為多維關聯陣列。
第二個參數是一個回呼函式,會對所有資料執行(例如,如果您想要修剪所有資料,就像 Julio 在他的函式中所做的那樣,只需將 'trim' 作為第二個參數傳遞即可)。
<?php
function unserialize_xml($input, $callback = null, $recurse = false)
/* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* 將 XML 字串反序列化為多維關聯陣列,可選用回呼函式處理所有非陣列資料
* 失敗時返回 false
* 注意:
* 根 XML 標籤將被移除
* 由於其遞迴特性,unserialize_xml() 也支援 SimpleXMLElement 物件和陣列作為輸入
* 使用 simplexml_load_string() 進行 XML 解析,詳情請參閱 SimpleXML 文件
*/
{
// 取得輸入,如果是遞迴的頂層,則使用 simplexml 載入 xml 字串
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
// 將 SimpleXMLElements 轉換為陣列
if ($data instanceof SimpleXMLElement) $data = (array) $data;
// 遞迴處理陣列
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
// 執行回呼函式並返回
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>
<?php
$xml = json_decode(json_encode((array) simplexml_load_string($string)), 1);
?>
提醒您,json_encode 會嘗試將資料轉換為 UTF-8,但它並不知道來源編碼。如果您沒有使用 UTF-8,此方法可能會導致編碼問題。
XML2Array 函式現在支援遞迴!
<?php
function XML2Array( $xml, $recursive = false )
{
if ( ! $recursive )
{
$array = simplexml_load_string( $xml ) ;
}
else
{
$array = $xml ;
}
$newArray = array() ;
$array = (array) $array ;
foreach ( $array as $key => $value )
{
$value = (array) $value ;
if ( isset( $value [ 0 ] ) )
{
$newArray [ $key ] = trim( $value [ 0 ] ) ;
}
else
{
$newArray [ $key ] = XML2Array( $value , true ) ;
}
}
return $newArray ;
}
?>
這是針對 Bob 的簡易 SimpleXML 包裝函式的更新版本。
我注意到他的版本會將空的 SimpleXMLElement 轉換成空的陣列。
<?php
/**
* https://php.dev.org.tw/manual/en/function.simplexml-load-string.php#91564
*
* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* 將 XML 字串反序列化為多維關聯陣列,可選用回呼函式處理所有非陣列資料
* 失敗時回傳 false
* 注意:
* 根 XML 標籤會被移除
* 由於其遞迴特性,unserialize_xml() 也支援 SimpleXMLElement 物件和陣列作為輸入
* 使用 simplexml_load_string() 進行 XML 解析,詳情請見 SimpleXML 文件
*
* @param $input
* @param null $callback
* @param bool $recurse
* @return array|mixed
*
*/
function unserialize_xml($input, $callback = null, $recurse = false)
{
// 取得輸入,如果是遞迴的頂層,則使用 simplexml 載入 xml 字串
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
// 將 SimpleXMLElements 轉換為陣列
if ($data instanceof SimpleXMLElement){
if(!empty($data)){
$data = (array) $data;
} else {
$data = '';
}
}
// 遞迴處理陣列
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
// 執行回呼函式並回傳
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>
使用 libxml_disable_entity_loader() 來限制外部檔案的載入。參考 http://www.idontplaydarts.com/2011/02/scanning-the-internal-network-using-simplexml/
如果要設定輸出 XML 的字元集,只需像這樣設定 encoding 屬性:
<?php simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><xml/>'); ?>
$xml->asXML 輸出的 XML 將包含像 'é' 這樣的重音字元,而不是 é。
希望這個有幫助
simplexml 無法簡單地使用 foreach 迴圈處理 CDATA 區段。
<?php
$sx = simplexml_load_string('
<test>
<one>hi</one>
<two><![CDATA[stuff]]></two>
<t>
<for>two</for>
</t>
<multi>one</multi>
<multi>two</multi>
</test>');
foreach((array) $sx as $tagname => $val) {
if (is_string($val)) {
// <one> 會在這裡
} elseif (is_array($val)) {
// <multi> 會在這裡,因為它出現多次
} elseif (is_object($val)) {
// <t> 會在這裡,因為它包含標籤
// <two> 會在這裡,因為它包含 CDATA!
}
}
?>
要在迴圈中測試,請執行以下操作
<?php
if (count((array) $val) == 0) {
// 這不是包含其他標籤的標籤
$val = '' . $val;
// 現在 CDATA 神奇地顯示出來了。
}
?>
包裝 XMLReader 類別,用於簡單的 SAX 讀取大型 XML
https://github.com/dkrnl/SimpleXMLReader
使用方法範例:http://github.com/dkrnl/SimpleXMLReader/blob/master/examples/example1.php
在疑惑了一段時間後,我才意識到一些事情(也許很明顯,但對我來說並非如此)。希望可以幫助其他人不要像我一樣浪費時間 :-P
當您有類似以下的內容時
<?php
$xmlstr = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<double xmlns="http://foosite.foo/">2328</double>
XML;
?>
您的 simpleXML 物件會被「轉換」成 text() 內容
<?php
$xml = simplexml_load_string($xmlstr);
echo $xml; // 這會輸出 2328 (字串)
?>
如果您想使用命名空間中存在的類別,請使用它的完整名稱。 simple_load_string 無法辨識簡短名稱。
class.new.php
<?php
namespace foo\bar;
class new extends SimpleXMLElement
{
public function do()
{
echo "done";
}
}
?>
false.php
<?php
use \foo\bar\new;
$result = simplexml_load_string($xml, 'new'); // 這會產生警告
$result->do(); // 致命錯誤
?>
true.php
<?php
use \foo\bar\new;
$result = simplexml_load_string($xml, '\foo\bar\new');
$result->do(); // 輸出 done
?>