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

對新奇的事物都很有興趣, 喜歡簡單的東西, 過簡單的生活.
本篇發表於 Programming 並標籤為 。將永久鏈結加入書籤。

PHP 使用 SimpleXML 遇到 Illegal offset type(型態轉換問題) 解法 有 2 則回應

  1. lp81sam 說道:

    昨天剛好遇到這樣的困擾
    剛好在www.php.net上看到有別種寫法
    提供給你參考
    http://www.php.net/manual/en/function.simplexml-load-string.php
    http://www.php.net/manual/en/function.simplexml-element-attributes.php

    Attributes() as $key=>$val)
    {
    if($key == $name)
    return (string)$val;
    }
    }

    }
    ...

    ...
    try {

    foreach ($story as $item) {

    $name = $item->getAttribute('name');
    $value = $item->getAttribute(0);

    $xmlarray[$name] = $value;

    }

    }
    .....略......
    }
    ?>

  2. Tsung 說道:

    原來如此, 我懂了... 主要是 getAttribute() 吧 🙂
    getAttribute() 的內部運作是:
    function getAttribute($name){
    foreach($this->attributes() as $key=>$val) {
    }
    }
    所以使用 foreach($this->attributes() as $key=>$val) 就可以把每個值拉出來, 然後再自行做處理.
    或者就是用 getAttribute() 直接拉值就可以了~~~

發表迴響