simpleXML - need a push please: can't found namespace element value. :s

Hello all,

I’m trying to echo: “example.pt” from the following XML:


<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
    <command>
        <renew>
            <domain:renew xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xsi:schemaLocation="urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd">
                <domain:name>example.pt</domain:name>
                <domain:curExpDate>2008-04-03</domain:curExpDate>
            </domain:renew>
        </renew>

        <extension>
            <ptdomain:renew xmlns:ptdomain="http://eppdev.dns.pt/schemas/ptdomain-1.0" xsi:schemaLocation="http://eppdev.dns.pt/schemas/ptdomain-1.0 ptdomain-1.0.xsd">
                <ptdomain:roid>26368</ptdomain:roid>
                <ptdomain:notRenew>true</ptdomain:notRenew>
            </ptdomain:renew>
        </extension>

        <clTRID>renew-02</clTRID>

        <bla>blabla 1</bla>

        <poing>Poing 1</poing>
        
        
    </command> 
</epp>

This works perfectly:


$xmlObj = simplexml_load_file('RepositorioXml/EppRenewResponse.xml');

foreach ($xmlObj->command as $comando)
{
    echo $comando->clTRID;
    echo '<br />';
    echo $comando->bla;
    echo '<br />';
    echo $comando->poing;
}

This doesn’t work - ie, I can’t see nothing displaying.
I have var_dump a lot after the first foreach and I’m always getting 0.


echo '<br /> Value inside namespaced elements:<br />';
foreach ($xmlObj->command as $comando)
{
//var_dump($comando); //getting: all nodes inside, including those with
//namespaces, but, those, however, are returned without any values, and
//object(SimpleXMLElement)#4 (0) are returned instead. :s

    //var_dump($comando->extension); //getting: object(SimpleXMLElement)#4 (0) { } 
    foreach ($comando->extension as $extensoes)
    {
        //var_dump($comando->extension); //getting: object(SimpleXMLElement)#8 (0) { } 
        $ns_domain = $extensoes->children('urn:ietf:params:xml:ns:domain-1.0');
        
        //var_dump($ns_domain); //getting: object(SimpleXMLElement)#8 (0) { }
        echo $ns_domain->name;
    }
}

Can anyone give me a hand here please?

Thanks a lot in advance,
Márcio

SOOOOOO… (:


/**
 * Loads a well formed xml file.
 * Converts that well formed xml file into a simpleXMLElement object instance ($xmlObj);
 *
 * If the nodes have children, their properties will be of type "object" (simpleXMLElement type object);
 * If the nodes don't have children, only values, those will be taken as strings.
 */
$xmlObj = simplexml_load_file('RepositorioXml/EppRenewResponse.xml');



/**
 * The node command as children, hence, it is a $xmlObj simpleXMLElement type - property.
 *
 * We are supposing several commands but, actually we will have always one.
 * So I believe this foreach could be removed hm?
 */
foreach ($xmlObj->command as $command)
{ 


    /**
     * Inside command property (that we have seen, it is an object), we have another element that as childs.
     * Renew. So, as the previous, this one will be a property of $command object, of type object.
     * (renew is treated as object (a simpleXMLElement) one.
     * Again, only one renew will be available, so we can supress this foreach I believe.
     */
    foreach ($command->renew as $renew)
    {

        /**
         * The children() method will find the children of the element that has been used to call it.
         * renew - on this case.
         * 
         * The children() method returns all child elements of a given XML node, on a given namesapce.
         * If any namespace if specified as method's param, ALL elements of the global namespace (those
         * contained on the first namespace URI, will be taken (if any)).
         *
         * The children() method accepts two params: 'namespace' and 'is_prefix'.
         *
         * If our nodes reference of our namespace is a given URI, we WILL NOT use is_prefix.
         * If the reference to our namespace is a prefix, then, we set is_prefix to TRUE.
         *
         * Domain is a prefix of renew node, bound to a given URI.
         * So, that's why we have TRUE on the line below.
         *
         *
         * Children(), will then return the childs of a given node,
         * that use a given prefix representating a specific namespace specification (given by the URN)
         *
         * Children() creates a simpleXMLElement object, containing, if exists,
         * the list of elements, specified on a given namespace-prefix-representation-object that are inside 
         * the object that calls children. In this case. Renew.
         *
         *
         *
         */
        $domainNamespace = $renew->children('domain', TRUE);


        /**
         * Our $domainNamespace (instance of simpleXMLElement) object, has now, the children of our renew node containing "domain"
         * namespace representation prefix.
         * Those children are converted as properties of a simpleXMLElement object. 
         * They are, in this case: "name" and "curExpDate".
         *
         * We hope, this is path that lead us to answer the initial question: 
         * Why do we access them, like this:
         * 
         * We are accessing our renew children that contain a specific prefix where, each of them, we be treated as properties,
         * and, on those properties, we have values, and are those values that we are echoing here: 
         */
         echo $domainNamespace->renew->name;
    }

}

Sir Salathe of the lucky surrounding landscapes, despite my obvious lacking on English proficiency, does this makes any sense?

K. Regards,
Márcio

About what I was doing, well… I didn’t really know. And I still don’t.
:s

When I var_dump this I don’t properly understand what I have here:

object(SimpleXMLElement)#5 (5) { [“renew”]=> object(SimpleXMLElement)#4 (0) { } [“extension”]=> object(SimpleXMLElement)#6 (0) { } [“clTRID”]=> string(8) “renew-02” [“bla”]=> string(8) “blabla 1” [“poing”]=> string(7) “Poing 1” }

Is an Object ok.

What about the #5 what does it mean? A cardinal there, don’t recall any on the past.

What about the (5) ? Maybe a size? But of what?
renew, extension, cITRID, they seem like keys of an associative array.
And they seem to have, as values, either “strings” or ints etc…, OR, an Object. If we have an Object we can iterate again… ?

How can we say this on one sentence? (:

I will now try to understand the code provided and post it back commented.

Ok… I will not dig in on this direction know, but yes, I was able to return the array with name spaces and then I asked, now what? I need the values as well… And the $prefix on SimpleXMLElement I thought it was something to do with the fact that we don’t have/need some sort of URI/URN/URL for our namespaces, and this is not the case, so I end up not reading more about it for the moment.

Ahhh… Code.
Commented code will follow for your consideration.

Thanks a lot!!

ps- I was doing something like this, before your post… at least I was getting the “two foreach” similary. (bad for all the rest).

Incomplete of course, anyway. I spend more time in sitepoint that with my family so I decided to share it. :smiley:

foreach ($xmlObj->renew as $renew)
{
    $ns_renew = $renew->children('urn:ietf:params:xml:ns:domain-1.0'):
    
    foreach ($renew as $domainRenew)
    {
        $ns_domain = $domainRenew->children('urn:ietf:params:xml:ns:domain-1.0');
        
        echo $ns_domain->name;
    }
}

So, domain namespace is a PREFIX of renew node element.
That’s why we have is_prefix attribute set to TRUE. Precise?

Then, we are storing ALL domain namespaces childs of renew (name and curExpDate - on this case), into a simpleXMLObject, where those namespaces will be treated as PROPERTIES.

If the above assumptions are correct, I’m not getting:
Properties of what? Of $domain ok.

//but why do he access them like this?

 echo $domain->renew->name;

//why not just:
$domain->name; ?

My use of -> is to access some object declared properties. I’m uncapable of imagine of what two -> -> could correspond on an Object structure. (if my question makes any sense).

Thanks in advance,
Márcio

Márcio, your second block of code does not work because you’re looping over the /epp/command/extension element (there is only one) but inside the inner foreach you’re trying to access the name element… shouldn’t you instead be looping over any renew elements rather than extension?

If you don’t want to access just the names (if you do, use XPath like Anthony suggested), and my assumptions about your XML structure are correct, then you could use something like the following to loop over the command and renew elements.


$xml = new SimpleXMLElement($xml);
foreach ($xml->command as $command) { // assumes multiple command elements
    foreach ($command->renew as $renew) { // assumes multiple renews per command
        // Access domain namespace
        $domain = $renew->children('domain', TRUE);
        var_dump((string) $domain->renew->name);
    }
}

P.S. SimpleXMLElement::getNamespaces just returns an array of the namespaces; it was most useful before the $prefix parameter was added to SimpleXMLElement::children.

Thanks a lot. Give me a few hours to start asking questions about it. :smiley:
I need to properly study it first.

[update]
Btw, do you, or anyone else, believe that, using:
getNamespaces(); can help here?

I just found this function, but I’m not yet sure if it fits…
[/update]

Thanks a lot for the push,
Márcio

ps- I’m putting the XMLs commands, each on their own file btw. :wink:
Then I call them, and I transform those into strings ready to be send… I’m loving this challenge. :slight_smile: Anyway, first things first… the namespace study…


<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
    <command>
        <renew>
            <domain:renew xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xsi:schemaLocation="urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd">
                <domain:name>example.pt</domain:name>
                <domain:curExpDate>2008-04-03</domain:curExpDate>
            </domain:renew>
        </renew>
        <extension>
            <ptdomain:renew xmlns:ptdomain="http://eppdev.dns.pt/schemas/ptdomain-1.0" xsi:schemaLocation="http://eppdev.dns.pt/schemas/ptdomain-1.0 ptdomain-1.0.xsd">
                <ptdomain:roid>26368</ptdomain:roid>
                <ptdomain:notRenew>true</ptdomain:notRenew>
            </ptdomain:renew>
        </extension>
        <clTRID>renew-02</clTRID>
        <bla>blabla 1</bla>
        <poing>Poing 1</poing>
    </command>
</epp>
';

$xml = new SimpleXMLElement($xml);
$xml->registerXpathNamespace('domain', 'urn:ietf:params:xml:ns:domain-1.0');
$node = $xml->xpath('//domain:name');
var_dump($node);
/*
  array(1) {
    [0]=>
    object(SimpleXMLElement)#2 (1) {
      [0]=>
      string(10) "example.pt"
    }
  }
*/

Any help Márcio?

I found it quick hard to traverse, I’m wondering whether domain:renew can be a valid child of renew, sure it’s namespaced but…

Off Topic:

I do expect Salathe to chime in, if only to correct my rather lacklustre attempt. :stuck_out_tongue: