X

PHP 使用 SimpleXML 遇到 Illegal offset type(型態轉換問題) 解法

PHP 的 simplexml_load_string/simplexml_load_file 很方便, 很簡單的就能把 XML parse 成 PHP Object, 然後就看要怎麼處理資料, 再處理即可~

做簡單的處理都沒什麼異常, 但是現在遇到要將 Object value 轉換成一般 PHP Array 的 key -> value 型態就遇到問題了. 不曉得是我不會用還是怎麼樣, 查不到正確該怎麼解, 所以寫起來紀錄一下.(希望有正確解法, 還請指導.. Orz)

註: PHP Version: PHP 5.2.3

先來看一段簡單的程式範例(原始程式):

<?php
$data = <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<response>
   <status>0</status>
   <result>
   <doc>
     <str name="title">title value</str>
     <str name="description">description value</str>
   </doc>
   </result>
</response>
EOF;

$xml = simplexml_load_string($data);

$results = array();
foreach ($xml->result->doc as $story) {
    $xmlarray = array();
    try {
        foreach ($story as $item) {
            $name = $item->attributes()->name;
            $value = $item->attributes()->{0};
            $xmlarray[$name] = $value; // have "Illegal offset type" error.
        }
    } catch (Exception $e) {
        echo 'Problem handling XML array.';
    }
    print_r($xmlarray);
}
?>

此程式目的是要 讀取 $data 的 XML, 然後轉換成 $xmlarray, 並指定 $xmlarray 的 KEY 是 Tag attribute name 的值, VALUE 就是 name Tag 包起來的值, 或者直接看希望的執行結果 如下:

Array
(
    [title] => title
    [description] => description
)

但是執行結果是 $xmlarray 都是空的, 主要是出現下述 Warning:

Warning: Illegal offset type in xml.php on line 24

然後 var_dump($name) 來看看, 是 Object 的結構如下:

object(SimpleXMLElement)#9 (1) {
  [0]=>
  string(5) "title"
}

很明顯就是要在存取進 object 的 [0] 即可, 但是發現我試著 $name[0], $name->{0}, 就是一直沒辦法單獨把值拿出來(用 $name[0], $name->{0} 用 var_dump() 都是同樣上述狀況), 而且一樣都是出現Illegal offset type的問題.

再來當然就網路找來找去, 似乎都沒有想說怎麼解(或許是我找的能力太差 Orz), 所以先放棄, 後來腦筋轉到型態轉換這邊去(想說型態一直轉不過來, 那我就強迫換型態好了).........就開始做做邪惡的事情囉~

於是我就對 $name 做 strval(), 沒想到一試就成功了~ 😛

所以程式改寫如下($data 沒變, 只修改最裡面 foreach, 先用 strval() 轉換型態):

<?php
$data = <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<response>
   <status>0</status>
   <result>
   <doc>
     <str name="title">title value</str>
     <str name="description">description value</str>
   </doc>
   </result>
</response>
EOF;

$xml = simplexml_load_string($data);

$results = array();
foreach ($xml->result->doc as $story) {
    $xmlarray = array();
    try {
        foreach ($story as $item) {
            $name = $item->attributes()->name;
            $value = $item->attributes()->{0};
            $name = strval($name); // 這邊用 $name/$name->{0} 都一樣
            $value = strval($value); // 這邊用 $value/$value->{0} 都一樣
            $xmlarray[$name] = $value;
        }
    } catch (Exception $e) {
        echo 'Problem handling XML array.';
    }
    print_r($xmlarray);
}
?>

這樣子執行後, $xmlarray 就是我們要的結果囉~ 😛

感謝 lp81sam 提供正解:

<?php
$data = <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<response>
   <status>0</status>
   <result>
   <doc>
     <str name="title">title value</str>
     <str name="description">description value</str>
   </doc>
   </result>
</response>
EOF;

$xml = simplexml_load_string($data);

$results = array();
foreach ($xml->result->doc as $story) {
    $xmlarray = array();
    try {
        foreach ($story as $item) {
            $$name = $item->getAttribute('name'); // use getAttribute()
            $value = $item->getAttribute(0);
        }
    } catch (Exception $e) {
        echo 'Problem handling XML array.';
    }
    print_r($xmlarray);
}
?>

getAttribute() 內部運行的模式大概如下:

public function getAttribute($name){
    foreach($this->attributes() as $key=>$val){
        if($key == $name){
            return (string)$val;
        }// end if
    }// end foreach
}// end function getAttribute

所以可以用 getAttribute() 去抓值, 或者跑 foreach 取值都可以 🙂 

Tsung: 對新奇的事物都很有興趣, 喜歡簡單的東西, 過簡單的生活.
Related Post