我正在使用SimpleXML尝试使用
我曾考虑过“预解析” XML文件,以在将文件内容传递给XML解析器之前去掉
(请原谅上面的任何错误术语;我已经很长时间没有完成此级别的XML了.)
解决方法:
看起来似乎是这样,但事实并非如此(除非您指定标志,尽管您没有在代码中显示您所做的事情,但我猜您不会这么做).仅当您使用-> asXML()方法而不通过to-string-implementation时,SimpleXML才能将其返回给您.
让我们做一些例子来演示它是如何工作的.我从DTD中选择了以下简单实体:
因此,让我们选择第一个< pos>元素,因为它包含& n;实体:
$xml = simplexml_load_file($file);
$pos = $xml->entry->sense->pos;
变量$pos现在是< pos>的SimpleXMLElement.元素节点.让我们输出它,以查看解析器对& n;做些什么.实体:
echo "SimpleXML value (string): ", $pos , "\n"
, "SimpleXML value (XML) : ", $pos->asXML(), "\n";
输出为:
SimpleXML value (string): noun (common) (futsuumeishi)
SimpleXML value (XML) : &n;
如本例所示,& n;仍然在那儿(< pos& n;< / pos>),只是当您将其作为字符串值(名词(普通)(futsuumeishi))访问时,它将被扩展.
顺便说一句,这完全可以,XML规范在这里说,是否扩展这些实体取决于解析器.对于SimpleXML的设计目的,在读取字符串值时,这完全可以扩展.
您甚至可以通过指定LIBXML_NOENT选项来控制此行为:
$xml = simplexml_load_file($file, NULL, LIBXML_NOENT);
这实际上将执行您假设的操作,现在扩展实体,XML输出不再包含该实体:
SimpleXML value (string): noun (common) (futsuumeishi)
SimpleXML value (XML) : noun (common) (futsuumeishi)
因此,现在出现双重问号了,该怎么做?嗯,PHP中的XML解析器实际上是实体模型,它是DOMDocument.它是SimpleXML的姊妹库,内部都共享相同的内存对象.这是不使用LIBXML_NOENT和使用LIBXML_NOENT的两种模式的同一对象(更精确的是:其唯一的子节点)的输出:
Mode 1:
DOMDocument Class : DOMEntityReference
DOMDocument value(XML) : &n;
DOMDocument ->nodeName : n
Mode 2 (LIBXML_NOENT):
DOMDocument Class : DOMText
DOMDocument value(XML) : noun (common) (futsuumeishi)
DOMDocument ->nodeName : #text
这是由以下代码创建的,这些代码应使给定输出背后的内容更清晰可见:
$node = dom_import_simplexml($pos);
$doc = $node->ownerDocument;
$entity = $node->firstChild;
echo "DOMDocument Class : ", get_class($entity) , "\n"
, "DOMDocument value(XML) : ", $doc->saveXML($entity), "\n"
, "DOMDocument ->nodeName : ", $entity->nodeName , "\n";
如所写,它是一个姊妹库,而dom_import_simplexml将$pos变成一个DOMElement,我们需要遍历该子元素的子元素,我们知道这是有问题的实体引用.
因此,现在这已经很有意义了:由于SimpleXML无法表示实体引用,因此只能提供扩展的字符串值或包含实体的XML.
否则,如何区别的字符串值
&n;
?因此,您所要求的只有有限的意义.但这并不意味着我们无法处理,因此可以通过扩展SimpleXML来欺骗SimpleXML.假设每个仅包含单个实体的子元素都应返回so.否则,应使用标准的SimpleXML stringyfication:
/**
* Class EntityPreserveXML
*/
class EntityPreserveXML extends SimpleXMLElement
{
/**
* @return string
*/
public function __toString()
{
$dom = dom_import_simplexml($this);
if (
!$dom instanceof DOMElement
|| $dom->childNodes->length !== 1
|| ! $dom->firstChild instanceof DOMEntityReference
) {
return parent::__toString();
}
return $dom->ownerDocument->saveXML($dom->firstChild);
}
}
让我们在上面的示例中运行它:
require('EntityPreserveXML.php');
$xml = simplexml_load_file($file, 'EntityPreserveXML');
$pos = $xml->entry->sense->pos;
echo "SimpleXML value (string): ", $pos , "\n"
, "SimpleXML value (XML) : ", $pos->asXML(), "\n";
SimpleXML现在正在使用扩展类,该扩展类将按预期提供:
SimpleXML value (string): &n;
SimpleXML value (XML) : &n;
& n;因为它是唯一的孩子,所以现在保留在SimpleXMLElement的字符串转换中.但是,仅因为这种方法不一定意味着您应该使用它,否则它就打破了文本形式的已解析XML与文档模型意义上的XML之间的编码边界.
可能您只是在寻找DOMDocument?这是一个具有更多详细信息的模型,您可以从中使用DOMEntityReferences(如果有).
标签:php,xml,simplexml
来源: https://codeday.me/bug/20191011/1889959.html