I am going through an XML file and trying to get the name of a child (or children) node(s) but I'm missing something. Even though there are child nodes, my foreach loop acts as if there is not.

        $pos = $node->sense->pos;

        foreach ($pos->children() as $child) {
            echo "I never get here";
            echo $child->getName() . "\n";
        }
        echo "but the node has children---<br>";
        print_r($pos);

The output looks like this

but the node has children---
SimpleXMLElement Object
(
    [n] => SimpleXMLElement Object
        (
        )

)
but the node has children---
SimpleXMLElement Object
(
    [adj-na] => SimpleXMLElement Object
        (
        )

)
but the node has children---
SimpleXMLElement Object
(
    [pn] => SimpleXMLElement Object
        (
        )

)

Any idea why the foreach doesn't go through the children or how I can get the name(s) of the child node?

Recommended Answers

All 7 Replies

can you post the (part of) xml-file?

Here's a sample.

<entry>
        <ent_seq>1000320</ent_seq>
        <k_ele>
            <keb>彼処</keb>
            <ke_pri>ichi1</ke_pri>
        </k_ele>
        <k_ele>
            <keb>彼所</keb>
        </k_ele>
        <r_ele>
            <reb>あそこ</reb>
            <re_pri>ichi1</re_pri>
        </r_ele>
        <r_ele>
            <reb>あすこ</reb>
        </r_ele>
        <r_ele>
            <reb>かしこ</reb>
        </r_ele>
        <r_ele>
            <reb>あしこ</reb>
            <re_inf>&ok;</re_inf>
        </r_ele>
        <r_ele>
            <reb>あこ</reb>
            <re_inf>&ok;</re_inf>
        </r_ele>
        <sense>
            <pos>&pn;</pos>
            <pos>&adj-no;</pos>
            <xref>何処</xref>
            <xref>此処</xref>
            <xref>其処</xref>
            <misc>&uk;</misc>
            <gloss>there (place physically distant from both speaker and listener)</gloss>
            <gloss>over there</gloss>
            <gloss>that place</gloss>
            <gloss>yonder</gloss>
        </sense>
        <sense>
            <stagr>あそこ</stagr>
            <stagr>あすこ</stagr>
            <pos>&n;</pos>
            <misc>&col;</misc>
            <gloss>genitals</gloss>
        </sense>
        <sense>
            <xref>あれほど</xref>
            <gloss>that far (something psychologically distant from both speaker and listener)</gloss>
            <gloss>that much</gloss>
            <gloss>that point</gloss>
        </sense>
    </entry>
    <entry>
        <ent_seq>1000360</ent_seq>
        <r_ele>
            <reb>あっさり</reb>
            <re_pri>ichi1</re_pri>
        </r_ele>
        <info>
            <audit>
                <upd_date>2012-08-04</upd_date>
                <upd_detl>Entry created</upd_detl>
            </audit>
            <audit>
                <upd_date>2012-08-04</upd_date>
                <upd_detl>Entry amended</upd_detl>
            </audit>
        </info>
        <sense>
            <pos>&adv-to;</pos>
            <pos>&vs;</pos>
            <misc>&on-mim;</misc>
            <gloss>easily</gloss>
            <gloss>readily</gloss>
            <gloss>quickly</gloss>
        </sense>
        <sense>
            <misc>&on-mim;</misc>
            <gloss>lightly (flavored food, applied makeup)</gloss>
        </sense>
    </entry>

In your exampele, &pn; &adj-no; and &n; are values of $node->sense->pos not child-elements

I can not get at is as a value, though I have been banging my head against the wall trying. I tried the following:

        $pos = $node->sense->pos;

        $posasstring=(string)$pos;
        echo $posasstring. 'pos <br>';
        //if ($pos->count()>0){
        foreach ($pos as $value) {
            echo "Value $value \n";
        }
        //}

        print_r($pos);
        echo "---<br>";

which outputs the following:

pos 
Value  
SimpleXMLElement Object
(
    [n] => SimpleXMLElement Object
        (
        )

)
---
pos 
Value  
SimpleXMLElement Object
(
    [n] => SimpleXMLElement Object
        (
        )

)
---
pos 
Value  
SimpleXMLElement Object
(
    [adj-na] => SimpleXMLElement Object
        (
        )

)
---
pos 
Value  
Value  
SimpleXMLElement Object
(
    [pn] => SimpleXMLElement Object
        (
        )

)
---

Looking at the output of print_r it seems that pos is an empty Object with a key of n, adj-na, or pn. but as you see I can not access the value. I tried to cast the object as a string based on this http://stackoverflow.com/questions/1133931/getting-actual-value-from-php-simplexml-node but that does not help. Sorry for the rant but I've spent hours on what should be a 5 minute problem.

Thank you for the feedback thus far. I have made a bit of progress.

I believe I have identified the source of the problem. The data that I can not get at is stored as an entity defined in the DTD. I can now get the first value in the set with:

$pos = $node->sense->pos;
        $posnode   = dom_import_simplexml($pos);
        $entity = $posnode->firstChild;

echo  "DOMDocument Class       : ", get_class($entity)    , "\n"
    , "DOMDocument value(XML)  : ", $doc->saveXML($entity), "\n"
        , "DOMDocument ->nodeName  : ", $entity->nodeName     , "\n";

Despite this progress, I am still not getting the data from the <pos> elements after the first one. I need to get multiple <pos> values within a <sense> </sense> and to get values from multiple <sense></sense> items within an entity.

Member Avatar for diafol

OK, I think I got it...

Convert to xml to parsable format (change bare & to &amp;):

function ampIt($loadFile,$saveFile)
{
    $lines = file($loadFile);
    $newlines = array();
    // Loop through our array, show HTML source as HTML source; and line numbers too.
    foreach ($lines as $line) {
        $newlines[] = preg_replace("/&(?!amp;)/",'&amp;',$line);
    }
    file_put_contents($saveFile, implode('', $newlines));   
}


$ampIt('entry2.xml','entry3.xml');

$XML = simplexml_load_file('entry3.xml');
print_r($XML);

Now shows as expected with SimpleXML. This now works for me...

$XML = simplexml_load_file('entry3.xml');

foreach($XML->entry as $entry)
{
    foreach($entry->sense as $sense)
    {
        foreach($sense->pos as $pos)
        {
            echo "Pos = " . $pos . "<br />"; 
        }
    }
}

Notice that I place <channel> around the xml. You should have something similar I would imagine?

Thank you both for the help. I could not replace "&" in entities, the file is just too big. having the nested foreach loops was the clue that I neeed. In case anyone is interested, my final working code looked like this:

        foreach ($node->sense as $sense) {
            //print_r($sense);
            //echo '<br>';
            $sense_num++;
            foreach ($sense->pos as $pos) {
                //$pos = $node->sense->pos;
                $posnode = dom_import_simplexml($pos);
                $doc = $posnode->ownerDocument;
                $entity = $posnode->firstChild;
                $posval = $entity->nodeName;
                unset($record);
                $record['dictionary_id'] = $dictionary_id;
                $record['sense']=$sense_num;
                $record['pos'] = $posval;
                echo '<pre>';
                                print_r($record);
                                echo '</pre>';
                dbRowInsert('pos', $record, $link);
            }
        }
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.