dongshungou7699 2016-11-17 15:55
浏览 63
已采纳

如何在PHP中从XML中删除实体声明

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

A little context:

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>
  • 写回答

1条回答 默认 最新

  • drwghu6386 2016-11-17 16:22
    关注

    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 ...
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 PADS Logic 原理图
  • ¥15 PADS Logic 图标
  • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
  • ¥20 气象站点数据求取中~
  • ¥15 如何获取APP内弹出的网址链接
  • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
  • ¥50 STM32单片机传感器读取错误
  • ¥15 (关键词-阻抗匹配,HFSS,RFID标签天线)
  • ¥15 机器人轨迹规划相关问题
  • ¥15 word样式右侧翻页键消失