SimpleXML has declaration of xmlns:xmlns="" - no way to remove
So infuriating, I can hardly talk. I've assembled an RSS feed with SimpleXML and yet - it's using name spaces, which are right now. But, it's constantly trying to declare xmlns:xmlns="" in the root node, when output. Even though I do no such thing.
It starts with
$rssXML->addAttribute("version", '2.0');
$rssXML->addAttribute("xmlns:media", "http://search.yahoo.com/mrss/", '');
$rssXML->addAttri开发者_Go百科bute("xmlns:dcterms", "http://purl.org/dc/terms/", '');
and after this I do:-
header("Content-Type: application/rss+xml");
echo $syndicationXML->asXML();
Yet it outputs :-
<?xml version="1.0"?>
<rss xmlns:xmlns="" version="2.0" xmlns:media="http://search.yahoo.com/mrss/" xmlns:dcterms="http://purl.org/dc/terms/"><channel>...
I do not understand all this namespace declaration. What's going on?
The problem with SimpleXML is that it's addAttribute
function adds an attribute, not a namespace and although it seems like it does what you want, it's not meant to be used the way you are using it.
It's meant to add a value that's part of a particular namespace (specified as the third parameter), not to add the namespace itself. The reason why you end up with xmlns:xmlns
is because SimpleXML found that you used the xmlns
namespace when specifying the name xmlns:media
for instance so it created an empty xmlns:xmlns
.
Here are 2 solutions to your problem:
1. Specify in the namespaces in the constructor.
$rssXML = new SimpleXMLElement('<rss xmlns:media="http://search.yahoo.com/mrss/" xmlns:dcterms="http://purl.org/dc/terms/" />');
$rssXML->addAttribute('version', '2.0');
2. Replace xmlns:xmlns=""
using preg_replace
echo preg_replace('/xmlns:xmlns=""\s?/', '', $rssXML->asXML());
You wrote that you want to remove that. Best way is to not put it in the first place.
This works by prefixing with xmlns:
(another time) - it somehow enables a special mode of operation in simplexml - and not providing an empty namespace-URI (otherwise you actually ask for adding that):
$rssXML = new SimpleXMLElement('<rss/>');
$rssXML->addAttribute("version", '2.0');
$rssXML->addAttribute("xmlns:xmlns:media", "http://search.yahoo.com/mrss/");
$rssXML->addAttribute("xmlns:xmlns:dcterms", "http://purl.org/dc/terms/");
$rssXML->asXML('php://output');
This creates the following output (beautified for your reading pleasure):
<?xml version="1.0"?>
<rss version="2.0"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:dcterms="http://purl.org/dc/terms/"/>
This "cheat" was originally hinted in "Unable to add Attribute with Namespace Prefix using PHP Simplexml" but was missing here.
SimpleXMLElement
can only add namespaces indirectly. Since you can only add element and attribute nodes, not namespace declarations, text nodes or other node types, you must somehow make use of SimpleXMLElement->addAttribute()
or SimpleXMLElement->addChild()
. The latter will only add new namespaces to the child, so it's of no use here. addAttribute()
will add the namespace along with an attribute to the given element, so if you then remove the attribute, you're left with the namespace as desired.
There isn't an obvious method of removing an attribute, but the use of unset
as shown in several answers to "Remove a child with a specific attribute, in SimpleXML for PHP" can be adapted to the task, using SimpleXMLElement->attributes()
to get a reference to the attribute.
<?php
$rssXML = new SimpleXMLElement('<rss/>');
$rssXML->addAttribute("version", '2.0');
# add a dummy attribute to get the namespace
$rssXML->addAttribute("media:_", '', "http://search.yahoo.com/mrss/");
unset($rssXML->attributes('media', TRUE)[0]);
# and again
$rssXML->addAttribute("dcterms:_", '', "http://purl.org/dc/terms/");
unset($rssXML->attributes('dcterms', TRUE)[0]);
echo $rssXML->asXML(), "\n";
Result:
<?xml version="1.0"?>
<rss xmlns:media="http://search.yahoo.com/mrss/" xmlns:dcterms="http://purl.org/dc/terms/" version="2.0"/>
The advantage this has over adding the namespace declaration as an attribute with a fake namespace prepended is it's treated as a namespace, rather than an attribute that happens to have something that looks like a namespace prefix in its name.
var_export($rssXML->getDocNamespaces());
Result:
array (
'media' => 'http://search.yahoo.com/mrss/',
'dcterms' => 'http://purl.org/dc/terms/',
)
精彩评论