2011-08-24 48 views
3

我需要將XML文檔轉換爲JSON,以便輕鬆訪問JavaScript中的數據。我目前使用這種方法將XML轉換成JSON:使用PHP將XML轉換爲JSON,同時保留陣列

json_encode(new SimpleXMLElement($xml, LIBXML_NOCDATA)); 

不過,我遇到了一個問題,當一個元素只包含1個元素。在使用SimpleXML進行分析時,它被視爲一個對象而不是數組。我希望它們始終被視爲數組,除非該元素只包含文本。

實施例:

$xml = <<<END 
<xml> 
    <TESTS> 
    <TEST>TEXT HERE</TEST> 
    </TESTS> 
</xml> 
END; 

echo json_encode(new SimpleXMLElement($xml, LIBXML_NOCDATA)); 

此輸出:

{"TESTS":{"TEST":"TEXT HERE"}} 

如果我下添加其他元件,則輸出是我希望它:

$xml = <<<END 
<xml> 
    <TESTS> 
    <TEST>TEXT HERE</TEST> 
    <TEST>MORE TEXT HERE</TEST> 
    </TESTS> 
</xml> 
END; 

echo json_encode(new SimpleXMLElement($xml, LIBXML_NOCDATA)); 

輸出:

{"TESTS":{"TEST":["TEXT HERE","TEXT HERE"]}} 

請注意,元素包含在JSON數組內而不是JSON對象中。有沒有辦法強制元素被解析爲數組?

+0

似乎你有對象,但第一種情況下這個元素的值是字符串,但第二個是數組。 –

+0

我想你必須走XML並手動轉換爲數組。即使有強制使用數組而不是對象的方法,那麼第一個示例最終會針對JSON:{「Tests」:[{「Test」:[「Text HERE」]}]}。我在想這不是你真正想要的。 –

+0

你正在傳入一個對象(類simplexml)......當然你會從json_encode中取出一個對象。 –

回答

2

我不得不面對同樣的情況。以下是該問題的第一個快速解決方案 - 適用於您的示例。

class JsonWithArrays 
{ 
    protected $root, $callback; 

    public function __construct(SimpleXMLElement $root) 
    { 
     $this->root = $root; 
    } 

    /** 
    * Set a callback to return if a node should be represented as an array 
    * under any circumstances. 
    * 
    * The callback receives two parameters to react to: the SimpleXMLNode in 
    * question, and the nesting level of that node. 
    */ 
    public function use_callback_forcing_array ($callback) 
    { 
     $this->callback = $callback; 
     return $this; 
    } 

    public function to_json() 
    { 
     $transformed = $this->transform_subnodes($this->root, new stdClass(), 0); 
     return json_encode($transformed); 
    } 

    protected function transform_subnodes (SimpleXMLElement $parent, stdClass $transformed_parent, $nesting_level) 
    { 
     $nesting_level++; 

     foreach($parent->children() as $node) 
     { 
      $name = $node->getName(); 
      $value = (string) $node; 

      if (count($node->children()) > 0) 
      { 
       $transformed_parent->$name = new stdClass(); 
       $this->transform_subnodes($node, $transformed_parent->$name, $nesting_level); 
      } 
      elseif (count($parent->$name) > 1 or $this->force_array($node, $nesting_level)) 
      { 
       $transformed_parent->{$name}[] = $value; 
      } 
      else 
      { 
       $transformed_parent->$name = $value; 
      } 
     } 

     return $transformed_parent; 
    } 

    protected function force_array ($node, $nesting_level) 
    { 
     if (is_callable($this->callback)) 
     { 
      return call_user_func($this->callback, $node, $nesting_level); 
     } 
     else 
     { 
      return false; 
     } 
    } 
} 

$xml = <<<END 
<xml> 
    <TESTS> 
    <TEST>TEXT HERE</TEST> 
    </TESTS> 
</xml> 
END; 

$xml2 = <<<END 
<xml> 
    <TESTS> 
    <TEST>TEXT HERE</TEST> 
    <TEST>MORE TEXT HERE</TEST> 
    </TESTS> 
</xml> 
END; 

// Callback using the node name. Could just as well be done using the nesting 
// level. 
function cb_testnode_as_array(SimpleXMLElement $node, $nesting_level) 
{ 
    return $node->getName() == 'TEST'; 
} 

$transform = new JsonWithArrays(new SimpleXMLElement($xml, LIBXML_NOCDATA)); 
echo $transform 
    ->use_callback_forcing_array('cb_testnode_as_array') 
    ->to_json(); 

echo PHP_EOL; 

$transform2 = new JsonWithArrays(new SimpleXMLElement($xml2, LIBXML_NOCDATA)); 
echo $transform2 
    ->use_callback_forcing_array('cb_testnode_as_array') 
    ->to_json(); 
0
echo json_encode(json_decode(json_encode(new SimpleXMLElement($xml, LIBXML_NOCDATA)), true)); 

真的,這是很多愚蠢的,但你首先如果所有轉換爲對象,然後在陣列解碼並轉換成JSON像數組風格..))

+0

試過了,沒有工作。返回{「TESTS」:{「TEST」:「TEXT HERE」}}就像OP發佈的代碼一樣。 – hashchange