• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • SimpleXMLElement::children()

    (PHP 5, PHP 7)

    Finds children of given node

    说明

    publicSimpleXMLElement::children([string $ns[,bool $is_prefix= FALSE]]): SimpleXMLElement

    This method finds the children of an element. The result follows normal iteration rules.

    Note:SimpleXML建起了一个给大多数方法添加迭代属性的规则。不能通过使用var_dump()或任何可检查对象的其它东西来查看。

    参数

    $ns

    An XML namespace.

    $is_prefix

    If$is_prefixis TRUE,$nswill be regarded as a prefix. If FALSE,$nswill be regarded as a namespace URL.

    返回值

    Returns a SimpleXMLElement element, whether the node has children or not.

    更新日志

    版本说明
    5.2.0 The optional parameter$is_prefixwas added.

    范例

    Example #1 Traversing achildren()pseudo-array

    <?php
    $xml = new SimpleXMLElement(
    '<person>
     <child role="son">
      <child role="daughter"/>
     </child>
     <child role="daughter">
      <child role="son">
       <child role="son"/>
      </child>
     </child>
    </person>');
    foreach ($xml->children() as $second_gen) {
        echo ' The person begot a ' . $second_gen['role'];
        foreach ($second_gen->children() as $third_gen) {
            echo ' who begot a ' . $third_gen['role'] . ';';
            foreach ($third_gen->children() as $fourth_gen) {
                echo ' and that ' . $third_gen['role'] .
                    ' begot a ' . $fourth_gen['role'];
            }
        }
    }
    ?>
    

    以上例程会输出:

    The person begot a son who begot a daughter; The person
    begot a daughter who begot a son; and that son begot a son
    

    Example #2 Using namespaces

    <?php
    $xml = '<example xmlns:foo="my.foo.urn">
      <foo:a>Apple</foo:a>
      <foo:b>Banana</foo:b>
      <c>Cherry</c>
    </example>';
    $sxe = new SimpleXMLElement($xml);
    $kids = $sxe->children('foo');
    var_dump(count($kids));
    $kids = $sxe->children('foo', TRUE);
    var_dump(count($kids));
    $kids = $sxe->children('my.foo.urn');
    var_dump(count($kids));
    $kids = $sxe->children('my.foo.urn', TRUE);
    var_dump(count($kids));
    $kids = $sxe->children();
    var_dump(count($kids));
    ?>
    
    int(0)
    int(2)
    int(2)
    int(0)
    int(1)
    

    注释

    SimpleXMLElement::children() returns a node object no matter if the current node has children or not. Use count() on the return value to see if there are any children. As of PHP 5.3.0,SimpleXMLElement::count() may be used instead.

    参见

    • SimpleXMLElement::count() Counts the children of an element
    • count()计算数组中的单元数目,或对象中的属性个数
    Here's a simple, recursive, function to transform XML data into pseudo E4X syntax ie. root.child.value = foobar
    <?php
    error_reporting(E_ALL);
    $xml = new SimpleXMLElement(
    '<Patriarch>
      <name>Bill</name>
      <wife>
       <name>Vi</name>
      </wife>
      <son>
       <name>Bill</name>
      </son>
      <daughter>
       <name>Jeri</name>
       <husband>
        <name>Mark</name>
       </husband>
       <son>
        <name>Greg</name>
       </son>
       <son>
        <name>Tim</name>
       </son>   
       <son>
        <name>Mark</name>
       </son>   
       <son>
        <name>Josh</name>
         <wife>
          <name>Kristine</name>
         </wife> 
         <son>
          <name>Blake</name>
         </son>
         <daughter>
          <name>Liah</name>
         </daughter>
       </son>
      </daughter>
    </Patriarch>');
    RecurseXML($xml);
    function RecurseXML($xml,$parent="")
    {
      $child_count = 0;
      foreach($xml as $key=>$value)
      {
       $child_count++;   
       if(RecurseXML($value,$parent.".".$key) == 0) // no childern, aka "leaf node"
       {
         print($parent . "." . (string)$key . " = " . (string)$value . "<BR>\n");    
       }   
      }
      return $child_count;
    }
    ?>
    The output....
    .name = Bill
    .wife.name = Vi
    .son.name = Bill
    .daughter.name = Jeri
    .daughter.husband.name = Mark
    .daughter.son.name = Greg
    .daughter.son.name = Tim
    .daughter.son.name = Mark
    .daughter.son.name = Josh
    .daughter.son.wife.name = Kristine
    .daughter.son.son.name = Blake
    .daughter.son.daughter.name = Liah
    Just a quick addition:
    If you need to access a child node which contains a dash, you need to encapsulate it with {""}.
    For example:
    <?php
    foreach ($domain->domain-listing as $product) {
    }
    ?>
    The example above doesn't work because of the dash. But instead you need to use:
    <?php
    foreach ($domain->{"domain-listing"} as $product) {
    }
    ?>
    At least for me the second example works perfectly fine.
    I made a slightly differnt approch towards the RecurseXML function. Beeing hungry I had problems with the code, as it did just overwrite two <maincourse>s. So here is what I did:
    <?php
    $xml = new SimpleXMLElement(
    '<meal>
      <type>Lunch</type>
      <time>12:30</time>
      <menu>
       <entree>salad</entree>
       <maincourse>
        <part>ships</part>
        <part>steak</part>
       </maincourse>
       <maincourse>
        <part>fisch</part>
        <part>rice</part>
       </maincourse>
       <maincourse>
        <part>wine</part>
        <part>cheese</part>
       </maincourse>
      </menu>
    </meal>');
    $vals = array();
    RecurseXML($xml,$vals);
    foreach($vals as $key=>$value)
     print("{$key} = {$value}<BR>\n");
    function RecurseXML($xml,&$vals,$parent="") {
     $childs=0;
     $child_count=-1; # Not realy needed.
     $arr=array();
        foreach ($xml->children() as $key=>$value) {
            if (in_array($key,$arr)) {
                $child_count++;
            } else {
                $child_count=0;
            }
            $arr[]=$key;
            $k=($parent == "") ? "$key.$child_count" : "$parent.$key.$child_count";
            $childs=RecurseXML($value,$vals,$k);
            if ($childs==0) {
                $vals[$k]= (string)$value;
            }
        }
     return $childs;
    }
    ?>
    Output is like this:
    type.0 = Lunch
    time.0 = 12:30
    menu.0.entree.0 = salad
    menu.0.maincourse.0.part.0 = ships
    menu.0.maincourse.0.part.1 = steak
    menu.0.maincourse.0 =
    menu.0.maincourse.1.part.0 = fisch
    menu.0.maincourse.1.part.1 = rice
    menu.0.maincourse.1 =
    menu.0.maincourse.2.part.0 = wine
    menu.0.maincourse.2.part.1 = cheese
    menu.0.maincourse.2 =
    menu.0 = 
    (Not beautiful, but it solved my case...)
    SimpleXMLElement::children can return null in this case:
    <?php 
    $xml = '
    <root attr="Hello"/>
    ';
    $sxe = new SimpleXMLElement($xml);
    $sxe_xpath = $sxe->xpath('/root/@attr')[0];
    $children = $sxe_xpath->children();
    var_export($children); // Is null
    ?>
    
    This is my recursive simple function to parse XML with attributes.
    <?php
    function ParseXML($node, &$parent=array(), $only_child=true) {     
        //Current node name
        $node_name = $node->getName();
         
        //Let's count children
        $only_child = true;
        if($node->count() > 1 ) $only_child = false;
        //If there is no child, then there may be text data
        if($only_child){
          $content="$node";      
          if (strlen($content)>0) $parent['content']=$content;
        }
        
        //Get attributes of current node
        foreach ($node->attributes() as $k=>$v) {
          $parent['@attributes'][$k]="$v";
        }
        
        //Get children
        $count = 0;
        foreach ($node->children() as $child_name=>$child_node) {
          if(!$only_child) //If there are siblings then we'll add node to the end of the array
            LGServerPVR::ParseXML($child_node, $parent[$node_name][$child_name][$count], $only_child);
          else 
            LGServerPVR::ParseXML($child_node, $parent[$node_name][$child_name], $only_child);
          $count++;
        }
        
        return $parent; 
        //(c) c01d[s]h!nE 10.12.2010    
      }
    ?>
    
    use this If you want to view the HTML as well as data.
    normal dumps display the parsed versions of HTML.
    This code displays the HTML as Text in a Text Area, and also display all other a data along side as an array 
    perfect for debugging (xml with html).
    Try This Code:
    <?php
    $xml = simplexml_load_file($url);
    function xml2array_parse($xml){
       foreach ($xml->children() as $parent => $child){
         $return["$parent"] = xml2array_parse($child)?xml2array_parse($child):"$child";
       }
       return $return;
     } 
     
     print "<pre><textarea style=\"width:200%;height:100%;\">";
     print_r(xml2array_parse($xml));
     print "</textarea></pre>";
    ?>
    
    The example below shows the basic use of depth-first recursion to span the xml tree.
    This is coded for the command line, and it prints out the original sentance above and then the copy cat sentence it creates itself for comparison, which as you will see; this example is slightly off from, I'll leave it upto you to resolve this issue.
    All in all I personaly think xml and recursion go hand in hand, so if you don't understand recursion but know xml and want to use php to manipulate xml you will need to learn about recursion at some point.
    <?php
    $xml = simplexml_load_string(
    '<person>
     <child role="son">
     <child role="daughter"/>
     </child>
     <child role="daughter">
     <child role="son">
      <child role="son"/>
     </child>
     </child>
    </person>');
    function recurse($child)
     {
      foreach($child->children() as $children) {
       echo ' who begot a '.$children['role'];
       recurse($children); 
      }
      return;
     }
    foreach($xml->children() as $children) {
     echo 'The person begot a '.$children['role'];
     recurse($children, 0);
     echo '; ';
    }
    echo "\n";
    echo 'The person begot a son who begot a daughter; The person begot a daughter who begot a son; and that son begot a son'."\n";
    ?>
    
    Here's my xml-to-array routine. Unlike many of the other comments here, this one takes namespaces into account.
    <?php
    class XmlArray {
     public function load_dom ($xml) {
      $node=simplexml_import_dom($xml);
      return $this->add_node($node);
     }
     
     public function load_string ($s) {
      $node=simplexml_load_string($s);
      return $this->add_node($node);
     }
     
     private function add_node ($node, &$parent=null, $namespace='', $recursive=false) {
     
      $namespaces = $node->getNameSpaces(true);
      $content="$node";
      
      $r['name']=$node->getName();
      if (!$recursive) {
       $tmp=array_keys($node->getNameSpaces(false));
       $r['namespace']=$tmp[0];
       $r['namespaces']=$namespaces;
      }
      if ($namespace) $r['namespace']=$namespace;
      if ($content) $r['content']=$content;
      
      foreach ($namespaces as $pre=>$ns) {
       foreach ($node->children($ns) as $k=>$v) {
        $this->add_node($v, $r['children'], $pre, true);
       }
       foreach ($node->attributes($ns) as $k=>$v) {
        $r['attributes'][$k]="$pre:$v";
       }
      }
      foreach ($node->children() as $k=>$v) {
       $this->add_node($v, $r['children'], '', true);
      }
      foreach ($node->attributes() as $k=>$v) {
       $r['attributes'][$k]="$v";
      }
      
      $parent[]=&$r;
      return $parent[0];
      
     }
    }
    ?>
    
    for XML namespaces such as <dc:creator> in RSS feeds use
    <?php
      $xml = new SimpleXMLElement($string);
      $item = $xml->channel[0]->item[0];
      $dc = $item->children("http://purl.org/dc/elements/1.1/");
      echo $dc->creator;
    ?>
    
    Ok so say you have this xml:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <!DOCTYPE nitf
    PUBLIC "-//IPTC-NAA//DTD NITF 3.1//EN"
        "http://www.nitf.org/site/nitf-documentation/nitf-3-1.dtd">
    <nitf>
     <head>
      <docdata management-status="embargoed">
       <!--data/2011/08/23/parties/doc4e53aa5783cca930694817.txt-->
       <doc-id id-string="doc4e53aa5783cca930694817"/>
       <date.release norm="20110823T000000"/>
       <key-list/>
      </docdata>
      <pubdata type="web" position.section="parties" position.sequence="0"/>
     </head>
    -- snip --
    If you need to access the nodes named "like.this" such as the date.release above, here is how I did it:
    $xml = new SimpleXMLElement($xhtml);
     echo (string)$xml->head->docdata->{"date.release"}["norm"];
    Took me a while to figure that one out ;)
    Transform xml to array php
    <?php
    function xml2phpArray($xml,$arr){
      $iter = 0;
        foreach($xml->children() as $b){
            $a = $b->getName();
            if(!$b->children()){
                $arr[$a] = trim($b[0]);
            }
            else{
                $arr[$a][$iter] = array();
                $arr[$a][$iter] = xml2phpArray($b,$arr[$a][$iter]);
            }
        $iter++;
        }
        return $arr;
    }
    $Array = simplexml_load_string(file_get_contents('myfile.xml'));
    print_r(xml2phpArray($Array,array()));
    ?>
    
    Sometimes you actually want an array, not a pseudo array.  This is especially true when you aren't dealing with attributes (i.e., you just want the array of child nodes).
    Do like this:
    <?php
    $children = $sxml->xpath('child::node()');
    ?>
    The reason you might want this is to be able to use array functions like array_shift, array_pop, etc. This is especially true when you are writing recursive functions. Simplexml works really well in iterative programming, but if you try to implement recursion it gets ugly.
    For anyone who hasn't read Sterling Hughe's article (http://www.zend.com/php5/articles/php5-simplexml.php):
    <?php
    $xml_document =<<<EOT
    <?xml version="1.0"?>
    <root xmlns:foo="http://example.com">
     <foo:bar>baz</foo:bar>
    </root>
    EOT;
    $xml_document = simplexml_load_xml($xml_document);
    $foo_ns_bar = $xml_document->children('http://example.com');
    echo $foo_ns_bar->bar[0]; // prints 'baz'
    ?>
    
    Just a warning that the iterable returned from children() contains the '@attributes' key, which is "invisible" during a foreach but can be seen if using a different construct, such as list()=each() or casting to an array before iterating w/ foreach.
    File:
    <category>
     <item>text</item>
     <bold>text</bold>
     <item>text</item>
     <item>text</item>
     <mark>text</mark>
     <bold>text</bold>
    </category>
    If you want to get also names of the tags, you can use this loop layout:
    <?php
    foreach($category -> children() as $name => $node){
     echo $name.'<br/>';
    }
    ?>