php/simplexml - LIBXML 选项被忽略了吗?

php/simplexml - LIBXML options ignored?

我正在尝试使用 LIBXML* 常量作为 SimpleXMLElement 构造函数的第二个参数,但它们根本没有改变任何东西。

$xml = '<root><empty_tag/><foo></foo></root>';
$simpleXml = new SimpleXMLElement($xml, LIBXML_NOENT|LIBXML_NOXMLDECL|LIBXML_NOEMPTYTAG);

$simpleXml->foo = 'Ņ';

echo $simpleXml->asXML();

预计:

<root><empty_tag></empty_tag><foo>Ņ</foo></root>

实际:

<?xml version="1.0"?>
<root><empty_tag/><foo>&#x145;</foo></root>

如您所见,这些标志中没有一个可以做任何事情 - 实体仍然被转义(尽管 XML 应该只转义 "'&>< 根据 https://www.w3.org/TR/xml/#syntax), XML 声明仍然存在,空标签仍然是空的。 有没有一种方法可以使用 SimpleXML 来达到预期的效果?或者至少 make 只转义 5 个特殊字符? addChild() 不是这里的选项,我正在分配现有节点。

您需要添加 XML 文档使用 UTF-8 编码的事实,例如...

$xml = '<?xml version="1.0" encoding="utf-8" ?><root><empty_tag/><foo></foo></root>';

给你...

<?xml version="1.0" encoding="utf-8"?>
<root><empty_tag/><foo>Ņ</foo></root>

这些常量的命名可能有点含糊。那么实际支持什么?

LIBXML_NOENT

实体是作为实体引用添加到文档中还是已展开。需要加载文档指定:

<?php

$xml = '<!DOCTYPE test [<!ENTITY c "TEST">]>
<test>&c;</test>';

echo (new SimpleXMLElement($xml))->asXML(), "\n";
echo (new SimpleXMLElement($xml, LIBXML_NOENT))->asXML(), "\n";

这显示了第一个输出:

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY c "TEST">
]>
<test>&c;</test>

实体已保留。对于第二个回声, LIBXML_NOENT:

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY c "TEST">
]>
<test>TEST</test>

XML借用了相关问答:

这与您的文档中的非 US-ASCII 字符无关。如果您需要包含文档,请将编码设置为 UTF-8,例如:

$xml = '<root><empty_tag/><foo></foo></root>';
$simpleXml = new SimpleXMLElement($xml);

dom_import_simplexml($simpleXml)->ownerDocument->encoding = 'UTF-8';

$simpleXml->foo = 'Ņ';

echo $simpleXml->asXML();

这里的技巧是 set the encoding in the underlying DOMDocument,这是我知道的 SimpleXMLElement(和 DOMDocument)的唯一方法。这里输出:

<?xml version="1.0" encoding="UTF-8"?>
<root><empty_tag/><foo>Ņ</foo></root>

您看不到更多 &#x145; 实体,而只是 Ņ Unicode(UTF-8 编码)实体。 XML declaration 现在也显示编码。

根据你的问题,我认为这就是你要找的 "for" LIBXML_NOENT.

LIBXML_NOXMLDECL

列表中的第二个。我从来没有让它工作,它有问题 and/or 有一些特定的版本要求,但老实说我什至不知道 if/where 有意应用它。

您可以从输出中删除包含 XML 声明的第一行(始终以“\n”结尾)。

或者您可以再次与基础 DOMDocument 相关以输出文档元素,因此它不是完整的文档,因此没有 XML 声明:

$dom = dom_import_simplexml($simpleXml)->ownerDocument;
echo $dom->saveXML($dom->documentElement);

输出:

<root><empty_tag/><foo>Ņ</foo></root>

这基本上是建议的内容:remove xml version tag when a xml is created in php

LIBXML_NOEMPTYTAG

列表中的第三个也是最后一个。我现在可以从 PHP 手册中引用,但这已经在其他地方完成 on site already 但无论如何,如何使用 SimpleXMLElement 执行此操作而不考虑常量不可用?

一种方法是再次通过 DOMDocument 提供选项:

$dom = dom_import_simplexml($simpleXml)->ownerDocument;
echo $dom->saveXML($dom->documentElement, LIBXML_NOEMPTYTAG);

输出:

<root><empty_tag></empty_tag><foo>Ņ</foo></root>

或者这样做 "pure" 简单 XML,每个空元素中的空文本节点:

$xml = '<?xml version="1.0" encoding="UTF-8"?><root><empty_tag/><foo></foo></root>';
$simpleXml = new SimpleXMLElement($xml);
$simpleXml->foo = 'Ņ';

foreach ($simpleXml->xpath('//*[not(*) and string() = ""]') as $empty) {
    $empty[0] = '';
}

echo $simpleXml->asXML();

foreach 中,获取每个 xpath 查询的所有空元素,然后将其文本内容设置为空字符串,如果没有,它将在其中插入一个文本节点(一个空的)一个呢。输出:

<?xml version="1.0" encoding="UTF-8"?>
<root><empty_tag></empty_tag><foo>Ņ</foo></root>

我希望这能为您提供所需的选项。