【问题标题】:How to remove entity declarations from XML in PHP如何在 PHP 中从 XML 中删除实体声明
【发布时间】:2017-04-01 06:17:25
【问题描述】:

我试图从 XML 文件中删除 <!ENTITY 定义但没有成功,我认为通过使用以下 sn-p 输出将不包含实体定义的痕迹,但我错了。

我怎样才能实现这个目标?

DOMDocument::loadXML(): xmlns: URI &ns_svg; is not absolute in Entity 旁边没有错误消息

一点上下文:

我将 SVG 嵌入到另一个 SVG 中,但 <!ENTITY 给我带来了各种问题,所以我正在考虑使用 LIBXML_NOENT 并删除所有 <!ENTITY 定义。

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">

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>

输出:

<?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>

【问题讨论】:

    标签: php xml svg


    【解决方案1】:

    您只能删除整个文档类型节点。实体似乎不是它的子节点。但在此之前,您应该使用 LIBXML_NOENT 替换实体:

    $document = new DOMDocument();
    $document->loadXML($xml, LIBXML_NOENT);
    
    $document->removeChild($document->doctype);
    
    echo $document->saveXML();
    

    保留我找到的文档类型的唯一方法是使用该文档类型创建一个新文档并将所有节点复制到其中。

    $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();
    

    文档类型节点不能导入到另一个文档中,DOMDcoument::importNode() 会为它返回FALSE

    如果您查看标准DOMDocumentType::entititesDOMNamedNodeMap 并且应该有一个方法removeNamedItem()。但如果你称它为 PHP 输出:

    Warning: DOMNamedNodeMap::removeNamedItem(): Not yet implemented in ... on line ...
    

    【讨论】:

    • 这有帮助,谢谢!你知道为什么我不能只删除实体而不是整个文档类型吗?
    • 我做了更多的实验,可以稍微优化一下。我不认为实体是文档类型的子节点。它是一个命名节点映射,就像属性一样。这可能是原因。或者只是因为它是文档的基本属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 2012-09-29
    相关资源
    最近更新 更多