1

I am writing a script to handle jsonp response. So that I can interpret it, send it to client, and use my own callback in ajax. Anyway, the response from server is json if it is successful. If the request fails, it returns an xml.

I checked some answers before.

Check whether returned file is XML or not

How check if a String is a Valid XML with-out Displaying a Warning in PHP

This answer works fine, my bad.

I write this.

$xml = simplexml_load_string($result,'SimpleXmlElement', LIBXML_NOERROR+LIBXML_ERR_FATAL+LIBXML_ERR_NONE);
if(!$xml){// json}

This gives out warning,

node no longer exist

The warning enters the json response, making it hard to parse.

I know if I suppress the warnings in php, it would work fine, but this is not the answer I want. I want to know, how do I check the string format, without giving out warning. Even in developing environment. I think it's better to solve problem from the root.

Then I used this,

$xml = simplexml_load_string($result,'SimpleXmlElement', LIBXML_NOERROR+LIBXML_ERR_FATAL+LIBXML_ERR_NONE);
if($xml == false){ // json }

This enters the block no matter if the string is xml or json. $xml == false is always evaluated as true.

I think if you can explain to me, the difference between $xml == false and !$xml that would be great. Thanks in advance.

Community
  • 1
  • 1
Max Luan
  • 305
  • 3
  • 9
  • Why not just send a different content-type header to send the string? If it's invalid use `text/plain` and if it's valid use `application/xml` or whatever you need. Then based on the content-type header, either parse the XML or display the error. – Mike Mar 11 '14 at 03:16
  • Thanks @Mike, but where are you suggesting me to do the checking? – Max Luan Mar 11 '14 at 03:29
  • Possible duplicate of http://stackoverflow.com/questions/4554233/how-check-if-a-string-is-a-valid-xml-with-out-displaying-a-warning-in-php. – Benjamin Nolan Mar 11 '14 at 03:42
  • @TwoWholeWorms no man, this is not a duplicate. In fact, I have the link in my question. – Max Luan Mar 11 '14 at 03:58
  • Well, the answer you don't want *is* the answer to your problem, as there is no other way to do it without using the iterative code I've linked below, which is a hell of a lot more inefficient. Sorry, mate. – Benjamin Nolan Mar 11 '14 at 04:01
  • @Mike I didn't think that way. Your answer solves my problem. – Max Luan Mar 11 '14 at 04:34

1 Answers1

2

Since a way to detect XML without parsing it has been asked for, the following regex should match a valid XML string, at least preliminarily:

^(<([a-zA-Z0-9]+)([\s]+[a-zA-Z0-9]+="[a-zA-Z0-9]+")*>([^<]*([^<]*|(?1))[^<]*)*<\/\2>)$

This can be tested here: http://regex101.com/r/mW9aZ5

However, I still assert that the libxml way is better. :)

-- Edit 1

Turns out this is a duplicate of: How check if a String is a Valid XML with-out Displaying a Warning in PHP

Tjirp's answer in that thread using libxml_use_internal_errors(true); is much more efficient. I suggest using that.

-- My original answer, which is inefficient

Edit: This requires iterating through every node in the XML tree calling ->isValid() for each node. ->isValid() ONLY checks the current node. It does not check the entire tree at once, as one would expect. It's also worth noting that the documentation on PHP.net is ambiguous and lacking complete useful usage examples. I've left this here rather than removing it for this reason.

You can use XMLReader::isValid() to validate that an opened XML file or string actually contains valid XML.

To load from the $result string itself:

$xml = new XMLReader();
$xml->xml($result);
$xml->setParserProperty(XMLReader::VALIDATE, true);
$success = true;
while ($xml->read()) {
    if (!$xml->isValid()) {
        $success = false;
    }
}
if ($success) {
    // Return valid response
} else {
    // Return invalid response
}

Alternatively, you can also load the XML from from a file on the filesystem:

$xml = new XMLReader();
$xml->open($file);
// Rest of code as above

Regarding if ($xml == false) always evaluating to true, this should never happen unless $xml is always false. Are you sure you didn't unintentionally write if ($xml = false) instead by accident?

Community
  • 1
  • 1
Benjamin Nolan
  • 1,170
  • 1
  • 10
  • 20
  • Sorry, i tried it, but why is even an arbitrary plain text string is regarded as valid? – Max Luan Mar 11 '14 at 03:25
  • That is a bloody good question, and I'm now looking into it for you. :/ – Benjamin Nolan Mar 11 '14 at 03:31
  • You work hard, I hope I can accept your answer. But the problem is not solved. As I stated, I if $xml is not valid, it is in jsonp format. Warning is given on `XMLRreader::read()`. My problem is here, if the string is definitely not xml. I am not saying xml with wrong format, but definitely OTHER format. Your answer would work fine with invalid xml. But if I feed other format, they give more warnings. – Max Luan Mar 11 '14 at 04:15
  • Well, as a horrible hack, `if (!preg_match('/^\s*', $result))` will at least tell you if it starts with a < (and some optional whitespace characters). However, I still think the answer given in the post you linked to is still your best bet, especially considering what you've just mentioned. – Benjamin Nolan Mar 11 '14 at 04:19
  • The hack works. Though ugly. The link you mentioned works. The first time tried it, i made some mistakes. Thanks a lot. If you update what you just said to you answer, I would accept it as the best answer. Thanks a lot. – Max Luan Mar 11 '14 at 04:31