PHP 使用 SimpleXML 遇到 Illegal offset type(型態轉換問題) 解法
PHP 的 simplexml_load_string/simplexml_load_file 很方便, 很簡單的就能把 XML parse 成 PHP Object, 然後就看要怎麼處理資料, 再處理即可~
- simplexml_load_string : 丟 XML 進去即可
- simplexml_load_file : 丟 URL 進去也吃, 拿來 Parse XML/RSS Feed 超方便
做
簡單的處理都沒什麼異常, 但是現在遇到要將 Object value 轉換成一般 PHP Array 的 key -> value
型態就遇到問題了. 不曉得是我不會用還是怎麼樣, 查不到正確該怎麼解, 所以寫起來紀錄一下.(希望有正確解法, 還請指導.. Orz)
註: PHP Version: PHP 5.2.3
先來看一段簡單的程式範例(原始程式):
<?php<br />$data = <<<EOF<br /><?xml version="1.0" encoding="UTF-8"?><br /><response><br /> <status>0</status><br /> <result><br /> <doc><br /> <str name="title">title value</str><br /> <str name="description">description value</str><br /> </doc><br /> </result><br /></response><br />EOF;<br />$xml = simplexml_load_string($data);<br />$results = array();<br />foreach ($xml->result->doc as $story) {<br /> $xmlarray = array();<br /> try {<br /> foreach ($story as $item) {<br /> $name = $item->attributes()->name;<br /> $value = $item->attributes()->{0};<br /> $xmlarray[$name] = $value; // have "Illegal offset type" error.<br /> }<br /> } catch (Exception $e) {<br /> echo 'Problem handling XML array.';<br /> }<br /> print_r($xmlarray);<br />}<br />?>
此程式目的是要 讀取 $data 的 XML, 然後轉換成 $xmlarray, 並指定 $xmlarray 的 KEY 是 Tag attribute name 的值, VALUE 就是 name Tag 包起來的值, 或者直接看希望的執行結果 如下:
Array<br />(<br /> [title] => title<br /> [description] => description<br />)
但是執行結果是 $xmlarray 都是空的, 主要是出現下述 Warning:
Warning: Illegal offset type in xml.php on line 24
然後 var_dump($name) 來看看, 是 Object 的結構如下:
object(SimpleXMLElement)#9 (1) {<br /> [0]=><br /> string(5) "title"<br />}
很
明顯就是要在存取進 object 的 [0] 即可, 但是發現我試著 $name[0], $name->{0},
就是一直沒辦法單獨把值拿出來(用 $name[0], $name->{0} 用 var_dump() 都是同樣上述狀況),
而且一樣都是出現Illegal offset type
的問題.
再來當然就網路找來找去, 似乎都沒有想說怎麼解(或許是我找的能力太差 Orz), 所以先放棄, 後來腦筋轉到型態轉換
這邊去(想說型態一直轉不過來, 那我就強迫換型態好了).........就開始做做邪惡的事情囉~
於是我就對 $name 做 strval(), 沒想到一試就成功了~
所以程式改寫如下($data 沒變, 只修改最裡面 foreach, 先用 strval() 轉換型態):
<?php<br />$data = <<<EOF<br /><?xml version="1.0" encoding="UTF-8"?><br /><response><br /> <status>0</status><br /> <result><br /> <doc><br /> <str name="title">title value</str><br /> <str name="description">description value</str><br /> </doc><br /> </result><br /></response><br />EOF;<br />$xml = simplexml_load_string($data);<br />$results = array();<br />foreach ($xml->result->doc as $story) {<br /> $xmlarray = array();<br /> try {<br /> foreach ($story as $item) {<br /> $name = $item->attributes()->name;<br /> $value = $item->attributes()->{0};<br /> $name = strval($name); // 這邊用 $name/$name->{0} 都一樣<br /> $value = strval($value); // 這邊用 $value/$value->{0} 都一樣<br /> $xmlarray[$name] = $value;<br /> }<br /> } catch (Exception $e) {<br /> echo 'Problem handling XML array.';<br /> }<br /> print_r($xmlarray);<br />}<br />?>
這樣子執行後, $xmlarray 就是我們要的結果囉~
感謝 lp81sam 提供正解:
<?php<br />$data = <<<EOF<br /><?xml version="1.0" encoding="UTF-8"?><br /><response><br /> <status>0</status><br /> <result><br /> <doc><br /> <str name="title">title value</str><br /> <str name="description">description value</str><br /> </doc><br /> </result><br /></response><br />EOF;<br />$xml = simplexml_load_string($data);<br />$results = array();<br />foreach ($xml->result->doc as $story) {<br /> $xmlarray = array();<br /> try {<br /> foreach ($story as $item) {<br /> $$name = $item->getAttribute('name'); // use getAttribute()<br /> $value = $item->getAttribute(0);<br /> }<br /> } catch (Exception $e) {<br /> echo 'Problem handling XML array.';<br /> }<br /> print_r($xmlarray);<br />}<br />?>
getAttribute() 內部運行的模式大概如下:
public function getAttribute($name){<br /> foreach($this->attributes() as $key=>$val){<br /> if($key == $name){<br /> return (string)$val;<br /> }// end if<br /> }// end foreach<br />}// end function getAttribute
所以可以用 getAttribute() 去抓值, 或者跑 foreach 取值都可以
------------------------------------------------------------------------------------------------------------
原來如此, 我懂了... 主要是 getAttribute() 吧
getAttribute() 的內部運作是:
function getAttribute($name){
foreach($this->attributes() as $key=>$val) {
}
}
所以使用 foreach($this->attributes() as $key=>$val) 就可以把每個值拉出來, 然後再自行做處理.
或者就是用 getAttribute() 直接拉值就可以了~~~