Search code examples
phpxmlreader

help in reading nested xml using xmlreader in php


<root>
  <thing>
    <specs>
      <spec1 />
      <spec3 />
      <spec2 />
    </specs>
    <details />
    <more_info>
      <info1 />
      <info2 />
    </more_info>
  </thing>
</root>


okeee so i got this sample xml and the problem is i cant seem to get the values of the innerxml,
when i use $reader->readInnerXML() it returns the whole string though im sure that my xml is valid
what i wanted was to get the values of spec1, spec2, spec3 separately

the code is pretty long so i posted it here
i've been stuck with this for 3days now T_T poor me, i'd gladly accept any corrections


Solution

  • It depends what you mean by "value". If you have something like

    <spec3 />Value</spec3>
    

    Then readInnerXML should be giving you your value.

    If your value is in an attribute,

    <spec1 foo="my attribute" />
    

    You'll need to use the getAttribute method of the XMLReader object, or explicitly tell the reader to start parsing attributes. See the code example below for a few ways to accomplish this.

    Finally, if the node contains more nested XML,

    <spec2><foo><baz thing="la de da">Value</baz></foo></spec2>
    

    There's no direct way at that moment in time for the reader to understand values/elements inside of it. You'd need to do one of the following

    1. Change you reader parsing code to hook into elements at those depths
    2. Take the XML chunk from readInnerXML and start parsing it with a second XMLReader instance,
    3. Take the XML chunk from readInnerXML and start parsing it with a another XML parsing library.

    Here's some example code for parsing attributes

    $reader = new XMLReader();
    $reader->xml(trim('
    <root>
      <thing>
        <specs>
          <spec1 foo="my attribute">Value</spec1>
          <spec3>
          My Text
          </spec3>
          <spec2 foo="foo again" bar="another attribute" baz="yet another attribute" />
        </specs>
        <details />
        <more_info>
          <info1 />
          <info2 />
        </more_info>
      </thing>
    </root> 
    '));
    
    $last_node_at_depth = array();
    $already_processed  = array();
    while($reader->read()){
        $last_node_at_depth[$reader->depth] = $reader->localName;
        if(
        $reader->depth > 0 && 
        $reader->localName != '#text' &&   
        $last_node_at_depth[($reader->depth-1)] == 'specs' &&
        !in_array ($reader->localName,$already_processed)
        ){          
            echo "\n".'Processing ' . $reader->localName . "\n";
            $already_processed[] = $reader->localName;
            echo '--------------------------------------------------'."\n";
            echo 'The Value for the inner node ';           
            echo ' is [';
            echo trim($reader->readInnerXML());
            echo ']'."\n";
    
            if($reader->attributeCount > 0){
                echo 'This node has attributes, lets process them' . "\n";
    
                //grab attribute by name
                echo '    Value of attribute foo: ' . $reader->getAttribute('foo') . "\n";
    
                //or use the reader to itterate through all the attributes
                $length = $reader->attributeCount;
                for($i=0;$i<$length;$i++){
                    //now the reader is pointing at attributes instead of nodes
                    $reader->moveToAttributeNo($i);
                    echo '    Value of attribute ' . $reader->localName;
                    echo ': ';
                    echo $reader->value;
                    echo "\n";
                }
            }
            //echo $reader->localName . "\n";        
        }        
    }