php / simplexml - параметры LIBXML игнорируются? - PullRequest
1 голос
/ 14 октября 2019

Я пытаюсь использовать константы LIBXML * для 2-го параметра конструктора 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? Или, по крайней мере, сделать только экранирование только 5 специальных символов? addChild() здесь не вариант,Я назначаю существующие узлы.

Ответы [ 2 ]

2 голосов
/ 15 октября 2019

Эти константы могут быть немного загадочными в своих именах. Так что же на самом деле поддерживается?

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 заимствован из связанных вопросов и ответов: Что делает LIBXML_NOENT (и почему он не называется LIBXML_ENT)?

Кстати, это не связано с символом не-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();

Хитрость заключается в том, чтобы установить кодировку в базовом DOMDocumentЭто единственный способ, который я знаю для SimpleXMLElementDOMDocument). Вот вывод:

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

Вы можете видеть не более &#x145; сущность, но вместо этого просто Ņ в Unicode (в кодировке UTF-8). XML-объявление теперь также показывает кодировку.

Исходя из вашего вопроса, я полагаю, это то, что вы ищете "1036 *.

LIBXML_NOXMLDECL

Второй в списке. Я никогда не заставлял его работать, он глючит и / или имеет некоторые специфические требования к версии, но, честно говоря, я даже не знаю, намеренно ли / где его применять.

Вы можете либо удалить первую строку (всегда "\n "прекращено), которое содержит декларацию XML из выходных данных.

Или вы можете снова связать базовый DOMDocument для вывода элемента документа, чтобы он не был полным документом и, следовательно, не имел декларации XML:

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

Вывод:

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

Это в основном то, что предлагается в: удалить тег версии xml при создании xml в php .

LIBXML_NOEMPTYTAG

Третий и последнийв списке. Я мог бы сейчас процитировать цитату из руководства по PHP, но это было сделано в другом месте на сайте уже , но в любом случае, как это сделать с SimpleXMLElement независимо от того, что константа недоступна?

В одну сторонубыло бы предоставить опцию через DOMDocument снова:

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

Вывод:

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

Или для выполнения этого "чистого" SimpleXML, пустого текстового узла в каждом пустом элементе:

$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, а затем установить его текстовое содержимое в пустую строку, которая будет вставлять туда текстовый узел, если естьпока нет (пустой). Outpupt:

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

Я надеюсь, что это даст вам варианты, которые вы искали.

1 голос
/ 14 октября 2019

Вам нужно добавить тот факт, что документ 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>
...