2013-11-21 73 views
2

之間我解析XML PHP中的SimpleXML,並有一個這樣的XML:的SimpleXML獲得元素含量的子元素

<xml> 
    <element> 
     textpart1 
      <subelement>subcontent1</subelement> 
     textpart2 
      <subelement>subcontent2</subelement> 
     textpart3 
    </element> 
</xml> 

當我做$xml->element這自然給了我整個元素,因爲在所有三個textparts。

所以,如果我解析到一個數組(帶有foreach爲孩子)這個我得到:

0 => textpart1textpart2textpart3, 1 => subcontent1, 2 => subcontent2 

我需要一種方法來解析<element>節點,以便每個停靠,或之後開始textpart子元素被視爲自己的元素。

結果我找了一個有序列表,可以在一個這樣的數組是明示:

0 => textpart1, 1 => subcontent1, 2 => textpart2, 3 => subcontent2, 4 => textpart3 

這是可能的,而不會改變XML文件?預先感謝任何提示!

回答

2

正如其他人所說,SimpleXML不支持以單獨實體的形式訪問單獨的文本節點,因此您需要用一些DOM方法來補充它。謝天謝地,您可以使用dom_import_simplexmlsimplexml_import_dom隨意切換。

的需要DOM功能的關鍵部分是:

  • 用於直接訪問所有節點的特定元件作爲下一個迭代列表れ>的childNodes成員變量
  • 的れ>節點類型爲可變確定一個特定的孩子是一個文本節點或元素
  • 的れ>的nodeValue變量獲得的實際文本

鑑於這些,你可以WR伊特兒童文本節點的函數返回與子元素的SimpleXML對象的混合數組和字符串,像這樣:

function get_child_elements_and_text_nodes($sx_element) 
{ 
    $return = array(); 

    $dom_element = dom_import_simplexml($sx_element); 
    foreach ($dom_element->childNodes as $dom_child) 
    { 
     switch ($dom_child->nodeType) 
     { 
      case XML_TEXT_NODE: 
       $return[] = $dom_child->nodeValue; 
      break; 
      case XML_ELEMENT_NODE: 
       $return[] = simplexml_import_dom($dom_child); 
      break; 
     } 
    } 

    return $return; 
} 

在你的情況,你需要遞歸下降樹,這使得它

function recursively_find_text_nodes($dom_element) 
{ 
    $return = array(); 

    foreach ($dom_element->childNodes as $dom_child) 
    { 
     switch ($dom_child->nodeType) 
     { 
      case XML_TEXT_NODE: 
       $return[] = $dom_child->nodeValue; 
      break; 
      case XML_ELEMENT_NODE: 
       $return = array_merge($return, recursively_find_text_nodes($dom_child)); 
      break; 
     } 
    } 

    return $return; 
} 

$text_nodes = recursively_find_text_nodes(dom_import_simplexml($simplexml->element)); 

Here's a live demo of that last function.

:如果你去混合DOM和SimpleXML,所以你可以寫,而不是完全在DOM的遞歸和運行它之前轉換的SimpleXML對象有點混亂
0

簡單的答案是否定的。 SimpleXML不實現對文本節點的任何形式的支持。
在這種情況下,您最好和首選的選項是使用DOMDocument

0

實際上,您正在查找所有屬於element元素節點的後代的文本節點。這可以表示爲以下XPath:

/*/element//text() 

即使SimpleXML的有一個xpath方法,做沒有任何錯誤,執行這個查詢,實際文本節點被轉換爲他們的父母元素節點。這是因爲SimpleXML的工作原理以及它的設計目的。

比較:

然而,與姐姐庫DOM文檔,可以自己表示文本節點的一些幫助,它是可以得到它的工作:

<?php 
/** 
* SimpleXML get Element Content between Child Elements 
* @link https://stackoverflow.com/q/20131226/367456 
*/ 

$buffer = <<<BUFFER 
<xml> 
    <element> 
     textpart1 
      <subelement>subcontent1</subelement> 
     textpart2 
      <subelement>subcontent2</subelement> 
     textpart3 
    </element> 
</xml> 
BUFFER; 

$xml = simplexml_load_string($buffer); 

$xpath = new SimpleXMLXpath($xml); 
$result = $xpath->query('/*/element//text()'); 
print_r($result); 

結果輸出則是:

Array 
(
    [0] => 
     textpart1 

    [1] => subcontent1 
    [2] => 
     textpart2 

    [3] => subcontent2 
    [4] => 
     textpart3 

) 

這是可能的,因爲SimpleXMLXpath類內包裝DOMXPath和stringifies結果的情況下,這是一個textnode的:

/** 
* Class SimpleXMLXpath 
* 
* @author hakre <http://hakre.wordpress.com/> 
*/ 
class SimpleXMLXpath 
{ 
    private $xml; 

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

    public function query($expression) 
    { 
     $context = dom_import_simplexml($this->xml); 
     $xpath = new DOMXPath($context->ownerDocument); 
     $result = []; 

     foreach ($xpath->query($expression, $context) as $node) { 
      switch (TRUE) { 
       case $node instanceof DOMText: 
        $result[] = $node->nodeValue; 
        continue; 

       case $node instanceof DOMElement: 
       case $node instanceof DOMAttr: 
        $result[] = simplexml_import_dom($node); 
        continue; 
      } 
     } 

     return $result; 
    } 
}