I'm trying to remove <!ENTITY
definitions from a XML file without success, I thought that by using the following snippet the output will contain no traces of entity definitions but I'm wrong.
How can I achieve this goal?
I get no error message beside the DOMDocument::loadXML(): xmlns: URI &ns_svg; is not absolute in Entity
I'm embedding an SVG inside another, but the <!ENTITY
gives me all kind of problem, so I'm thinking of using LIBXML_NOENT
and deleting all the <!ENTITY
definitions.
The PHP:
<?php
header('Content-Type: text/plain');
$str = file_get_contents(dirname(__FILE__) . '/test2.svg');
$document = new DOMDocument();
$document->loadXML($str);
foreach ($document->doctype->entities as $entity) {
$entity->parentNode->removeChild($entity); // I thought this would remove the <!ENTITY declaration
}
echo $document->saveXML(); // --> I want the XML without <!ENTITY ns_svg "http://www.w3.org/2000/svg"> and <!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
The XML:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_svg "http://www.w3.org/2000/svg">
<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
]>
<svg version="1.1"
id="Bundesschild" sodipodi:version="0.32" xmlns:cc="http://web.resource.org/cc/" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" inkscape:version="0.43" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" sodipodi:docbase="D:\Kuvat\Wikipedia" sodipodi:docname="Flag_of_Germany_(state).svg"
xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="250" height="275" viewBox="0 0 250 275"
overflow="visible" enable-background="new 0 0 250 275" xml:space="preserve">
<path id="Schild" fill="#FFCE00" stroke="#000000" d="M235.885,2.558c0,0,0,131.825,0,171.735
c0,54.121-50.504,98.265-112.501,98.265c-61.996,0-112.5-44.144-112.5-98.265c0-39.91,0-171.735,0-171.735H235.885z"/>
</svg>
The output:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_svg "http://www.w3.org/2000/svg"> <!-- Why this is still here???? -->
<!ENTITY ns_xlink "http://www.w3.org/1999/xlink"> <!-- Why this is still here???? -->
]>
<svg xmlns:cc="http://web.resource.org/cc/" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" version="1.1" id="Bundesschild" sodipodi:version="0.32" inkscape:version="0.43" sodipodi:docbase="D:\Kuvat\Wikipedia" sodipodi:docname="Flag_of_Germany_(state).svg" width="250" height="275" viewBox="0 0 250 275" overflow="visible" enable-background="new 0 0 250 275" xml:space="preserve">
<path id="Schild" fill="#FFCE00" stroke="#000000" d="M235.885,2.558c0,0,0,131.825,0,171.735 c0,54.121-50.504,98.265-112.501,98.265c-61.996,0-112.5-44.144-112.5-98.265c0-39.91,0-171.735,0-171.735H235.885z"/>
</svg>
You can only remove the whole document type node. The entities does not seem to be child nodes of it. But before that you should substitute the entities using the LIBXML_NOENT
:
$document = new DOMDocument();
$document->loadXML($xml, LIBXML_NOENT);
$document->removeChild($document->doctype);
echo $document->saveXML();
The only way to keep the document type I found, was creating a new document with the document type and copy all nodes into it.
$document = new DOMDocument();
$document->loadXML($xml, LIBXML_NOENT);
$existingDocumentType = $document->doctype;
if (NULL !== $existingDocumentType) {
$implementation = new DOMImplementation;
$newDocumentType = $implementation->createDocumentType(
$existingDocumentType->name,
$existingDocumentType->publicId,
$existingDocumentType->systemId
);
$newDocument = $implementation->createDocument(null, null, $newDocumentType);
foreach ($document->childNodes as $node) {
$copy = $newDocument->importNode($node, TRUE);
if ($copy) {
$newDocument->appendChild($copy);
}
}
$document = $newDocument;
}
echo $document->saveXML();
Document type nodes can not be imported into another document, DOMDcoument::importNode()
will return FALSE
for it.
If you look at the standard DOMDocumentType::entitites
is a DOMNamedNodeMap
and should have a method removeNamedItem()
. But if you call it PHP outputs:
Warning: DOMNamedNodeMap::removeNamedItem(): Not yet implemented in ... on line ...