Andreas Frick Andreas Frick - 3 months ago 17
PHP Question

Create SimpleXMLElement Node with Namespace and prevent namespace repeating

For a google sitemap I want to create XML nodes with namespace. How can I prevent simplexml from inserting the namespace on each node.

Structure that I need:

<xhtml:link
rel="alternate"
hreflang="de"
href="http://www.example.com/deutsch/"
/>


Structure from my code:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>www.url.ch</loc>
<xhtml:link xmlns:xhtml="xhtml" rel="alternate" hreflang="de-CH" href="www.url.ch/de">www.url.ch/de</xhtml:link>
<xhtml:link xmlns:xhtml="xhtml" rel="alternate" hreflang="fr-CH" href="www.url.ch/fr">www.url.ch/fr</xhtml:link>
</url>
</urlset>


My Code:

$rootNode = new SimpleXMLElement(
'<?xml version="1.0" encoding="utf-8"?>' .
' <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"></urlset>'
);

$urlNode = $rootNode->addChild('url');
$urlNode->addChild('loc', 'www.url.ch');

foreach (['de', 'fr', 'it', 'en'] as $locale) {
if (in_array($locale, ['it', 'en'])) {
continue;
}

$localeNode = $urlNode->addChild(
'xhtml:link',
'www.url.ch' . '/' . $locale,
'xhtml'
);

$localeNode->addAttribute('rel', 'alternate');
$localeNode->addAttribute('hreflang', $locale . '-CH');
$localeNode->addAttribute('href', 'www.url.ch' . '/' . $locale);
}

$rootNode->saveXML($filePath);

Answer

You need to specify the namespace in the addChild call as the globally unique "namespace identifier" (URI) not the "local prefix". So in this case, you are binding the xhtml prefix as xmlns:xhtml="http://www.w3.org/1999/xhtml" so the namespace URI is http://www.w3.org/1999/xhtml:

$localeNode = $urlNode->addChild(
    'xhtml:link',
    'www.url.ch' . '/' . $locale,
    'http://www.w3.org/1999/xhtml'
);

The XML library then looks up the already-assigned prefix for this namespace when generating the XML, and gives the desired result.