1

I understand how to call children in .xml documents by parsing with simplexml, however I'm having a problem calling a child with a name that looks like this:name2.

To be more specific, I'm trying to echo nhc:center from this .xml document: http://www.nhc.noaa.gov/nhc_ep4.xml.

Currently my code looks like this:

<?php
$xml=simplexml_load_file("http://www.nhc.noaa.gov/nhc_ep4.xml") or die("Error: Cannot create object");
echo $xml->channel->title[0] . "<br>";
echo $xml->channel->description[0] . "<br><br>";
echo $xml->channel->item[0]->nhc:Cyclone->nhc:center . "<br>";
?>

The first three lines work perfectly, however I return this error when trying to call nhc:center:

Parse error: syntax error, unexpected ':', expecting ',' or ';' in C:\xampp\htdocs\test.php on line 5

I'm sure it's something simple I'm missing here, any help is greatly appreciated!

Don
  • 3,876
  • 10
  • 47
  • 76
USTropics
  • 77
  • 12

3 Answers3

0

Colons are not valid in naked object attribute names, so you have to quote them:

$xml->channel->item[0]->{'nhc:Cyclone'}->{'nhc:center'}
Alex Howansky
  • 50,515
  • 8
  • 78
  • 98
  • A `:` in an XML tag denotes the namespace, and is not part of the element name, so this will not give the correct value. Instead, you need to use the `->children()` method to select the correct namespace. – IMSoP Jun 28 '17 at 15:46
0

Edit 2

A day after this answer was accepted, a less "hacky" answer was posted here: https://stackoverflow.com/a/44813107/713874

Original Reply

Try wrapping the name in curly-brackets and quotation marks, like this:

echo $xml->channel->item[0]->{'nhc:Cyclone'}->{'nhc:center'} . "<br>";

Source: How do I access this object property with a hyphenated name?

Edit: I noticed your domains were all public and saw it still wasn't grabbing your info. Weird. I did find this work-around that solved it:

$xml = simplexml_load_string(str_replace("nhc:", "nhc", file_get_contents("http://www.nhc.noaa.gov/nhc_ep4.xml")));

Bing
  • 3,071
  • 6
  • 42
  • 81
  • That certainly removed the error, however echo $xml->channel->item[0]->{'nhc:Cyclone'}->{'nhc:center'} . "
    "; will not return any values now
    – USTropics Jun 27 '17 at 17:58
  • 1
    That's a new question entirely, but I would start with: What do you get if you `var_dump($xml->channel)`? – Bing Jun 27 '17 at 18:04
  • 1
    @USTropics I was able to reproduce your problem and updated my answer with a work-around solution. – Bing Jun 27 '17 at 18:17
  • That works perfectly, thank you so much for the workaround! – USTropics Jun 27 '17 at 18:24
  • 1
    It's a hack, but it looks like it will solve your needs. If this was a good answer, don't forget to accept :) – Bing Jun 27 '17 at 18:25
  • I have and thanks again for all the help. That hack will save me a lot of frustration and time :D – USTropics Jun 27 '17 at 18:41
  • Like I said, it's a hack, but it worked on my server and his (for the specific URL provided), so it definitely works. – Bing Jun 28 '17 at 16:12
  • @IMSoP That's because your first example wasn't the code I provided at all. The "hack" (as I called it) I provided did a `str_replace` to remove the namespace issues before the child call. If you actually try my solution, you'll find it works: https://3v4l.org/Eke39 – Bing Jun 28 '17 at 21:44
  • @Bing Ah, I didn't even spot the hack. OK, I take back the claim that it won't work, but don't take back my downvote, because that is just horrible. Once you know what the colon means, it's really not hard to do this properly. – IMSoP Jun 28 '17 at 21:53
  • @IMSoP Fair enough, but until now I didn't even see the correct answer posted here. I have since updated my answer to reference yours. – Bing Jun 28 '17 at 23:13
-1

This has been asked hundreds of times, but the answers are often misleading or over-specific, so since I can't find a nice canonical answer to mark this as a duplicate, here's yet another summary:

  • Colons (:) in tag names denote that the tag is in a "namespace".
  • The part before the colon is the "namespace prefix"; it's local to this particular document, and could change without notice without the meaning of the document changing (e.g. if the file was generated or processed by a different application).
  • The "namespace identifier" is mapped to this with the xmlns attribute at the top of the file, and is formatted as a URL. The URL doesn't point anywhere, it's just a way for someone to "own" the namespace.
  • In this case xmlns:nhc="http://www.nhc.noaa.gov" maps the prefix nhc: to the namespace http://www.nhc.noaa.gov
  • In SimpleXML, you access elements in a namespace using the ->children() method, and attributes in a namespace using the ->attributes() method. These "switch" the namespace you're looking at when you use ->foo, ['bar'], etc.
  • You can use the prefix as the argument to ->children() or ->attributes(), but as I say, this might change, so what I normally do is set a constant somewhere to the URL, so I have my own short identifier for it and don't have to paste the URL in multiple places.

Long story short, you need to write this:

// Define a constant to refer to the namespace
// could be a variable, a class constant, or whatever you like
define('XMLNS_NHC', 'http://www.nhc.noaa.gov');

// Use ->children() to switch to that namespace
echo $xml->channel->item[0]->children(XMLNS_NHC)->Cyclone->center;
IMSoP
  • 89,526
  • 13
  • 117
  • 169