看起来可能是这样,但事实并非如此(除非你指定了我猜你没有在代码中显示你所做的事情的标志)。只是 SimpleXML 只能在您使用 ->asXML() 方法而不是通过 to-string-implementation 时返回给您。
让我们做一些例子来演示它是如何工作的。我从 DTD 中选择了这个简单的实体:
<!ENTITY n "noun (common) (futsuumeishi)">
所以让我们选择第一个 <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) : <pos>&n;</pos>
如本例所示,&n; 仍然存在 (<pos>&n;</pos>),只是在您将其作为字符串值 (noun (common) (futsuumeishi)) 访问时它会被扩展。
顺便说一句,这完全没问题,XML 规范在这里说,是否扩展这些实体取决于解析器。对于 SimpleXML 的设计目的,这完全可以在读取字符串值时扩展。
您甚至可以通过指定 LIBXML_NOENT 选项来控制此行为:
$xml = simplexml_load_file($file, NULL, LIBXML_NOENT);
这实际上会按照您当时的假设进行,实体现在已展开,XML 输出确实 不 不再包含实体:
SimpleXML value (string): noun (common) (futsuumeishi)
SimpleXML value (XML) : <pos>noun (common) (futsuumeishi)</pos>
所以现在双问号怎么做你要找的?嗯,PHP 中实际上有实体模型的 XML 解析器是 DOMDocument。它是 SimpleXML 的姐妹库,内部共享相同的内存对象。这是没有和有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。
否则会有什么不同的字符串值的方式
<pos>&n;</pos>
<pos><![CDATA[&n;]]></pos>
?所以你所要求的只有有限的意义。然而,这并不意味着我们无法处理这个问题,因此可以通过扩展 SimpleXML 来欺骗 SimpleXML 来做到这一点。假设每个仅包含单个实体的子元素都应返回 so。否则应使用标准 SimpleXML 字符串化:
/**
* 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) : <pos>&n;</pos>
&n; 作为唯一的子元素现在保留在 SimpleXMLElement 的字符串转换中。但仅仅因为这个工作并不意味着你应该使用它,它打破了以文本形式解析的 XML 和文档模型意义上的 XML 之间的编码边界。
您可能只是在寻找 DOMDocument?这是一个包含更多细节的模型,如果有的话,您可以使用DOMEntityReferences。