2013-11-21 41 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; 
    } 
}