问题
I have this code :
$xml = new SimpleXMLElement('<myxml></myxml>');
$xml->addChild('testNode attr="test Attribute"');
$node = $xml->addChild('erroNode attr="My Child node causes error -> expect >"');
//$node->addChild('nodeChild attr="node Child"');
header('Content-type: text/xml');
echo $xml->asXML();
exit();
I can create a childnode with attributes via $xml
, but not with $node
(child's child), Why? i get the error error on line 2 at column 66: expected '>'
From the docs it say that the addChild function returns a SimpleXmlElement of the child.
Check by uncommenting the commented line $node->addChild('nodeChild attr="node Child"');
Also it only happens when header is sent, if i comment header and do like below i can see the correct xml in page source :
$xml = new SimpleXMLElement('<myxml></myxml>');
$xml->addChild('testNode attr="test Attribute"');
$node = $xml->addChild('erroNode attr="My Child node causes error -> expect >"');
$node->addChild('nodeChild attr="node Child"');
//header('Content-type: text/xml');
echo $xml->asXML();
exit();
My PHP version is 5.4.9
回答1:
The error you are seeing is not coming from SimpleXML, but from your browser - that's why changing the HTTP header works. With this line, the browser knows the page is XML, and checks that it's valid; without it, it assumes it's HTML, and is more lenient:
header('Content-type: text/xml');
If you use "View Source" in your browser, you'll find that the actual output from PHP is the same in both cases. Another nice test is to set the content-type to text/plain
instead, which means the browser won't interpret the output at all, just show it as-is.
So, for some reason, SimpleXML is generating invalid XML. This is because the ->addChild() method takes as its first argument just the name of the element to add, in your case 'erroNode'
; you are passing in an invalid name that also includes attributes, which should be added later with ->addAttribute().
If we simplify the example a bit further, and look at the XML generated, we can see what's going on (here's an online demo):
// Make browser show plain output
header('Content-type: text/plain');
// Working example
$xml = new SimpleXMLElement('<myxml></myxml>');
$xml->addChild('testNode attr="test Attribute"');
echo $xml->asXML();
echo "\n";
// Broken example
$xml = new SimpleXMLElement('<myxml></myxml>');
$node = $xml->addChild('testNode attr="test Attribute"');
$node->addChild('test');
echo $xml->asXML();Child('testNode attr="test Attribute"');
$node->addChild('test');
echo $xml->asXML();
This outputs the below:
<?xml version="1.0"?>
<myxml><testNode attr="test Attribute"/></myxml>
<?xml version="1.0"?>
<myxml><testNode attr="test Attribute"><test/></testNode attr="test Attribute"></myxml>
The first version of the XML appears to be doing the right thing, because it has created a "self-closing tag". However, in the second, you can see that SimpleXML thinks that the tag name is 'testNode attr="test Attribute"'
, not just 'testNode'
, because that's what we told it.
The result is that it tries to put a closing tag with that "name", and ends up with </testNode attr="test Attribute">
, which isn't valid XML.
Arguably, SimpleXML should protect you against this kind of thing, but now that you know, you can easily fix the code (demo):
// Make browser show plain output
header('Content-type: text/plain');
// Fixed example
$xml = new SimpleXMLElement('<myxml></myxml>');
$node = $xml->addChild('testNode');
$node->addAttribute('attr', 'test Attribute');
$node->addChild('test');
echo $xml->asXML();
Now, SimpleXML knows that the tag is just called 'testNode'
, so can create the correct closing tag when it needs to:
<?xml version="1.0"?>
<myxml><testNode attr="test Attribute"><test/></testNode></myxml>
来源:https://stackoverflow.com/questions/21379760/simplexml-addchild-issue-when-header-sent