Обоснование обработки SimpleXMLElement текстовых значений в addChild и addAttribute
Разве это не противоречивое поведение? (PHP 5.2.6)
<?php
$a = new SimpleXMLElement('<a/>');
$a->addAttribute('b', 'One & Two');
//$a->addChild('c', 'Three & Four'); -- results in "unterminated entity reference" warning!
$a->addChild('c', 'Three & Four');
$a->d = 'Five & Six';
print($a->asXML());
Визуализирует:
<?xml version="1.0"?>
<a b="One & Two">
<c>Three & Four</c>
<d>Five & Six</d>
</a>
На bugs.php.net они отвергают все представления об этом, говоря об этом. Почему это возможно? Кстати, в документах ничего не говорится об этом несоответствии экранировки текстовых значений SimpleXMLElement.
Может ли кто-нибудь убедить меня в том, что лучшее решение для дизайна API возможно?
Ответы
Ответ 1
Чтобы убедиться, что мы на одной странице, у вас есть три ситуации.
-
Вставка амперсанда в атрибут с помощью addAttribute
-
Вставка амперсанда в элемент с помощью addChild
-
Вставка амперсанда в элемент путем перегрузки свойств
Это несоответствие между 2 и 3, которое вас сбило с толку. Почему AddChild автоматически не избежать амперсанд, в то время как при добавлении свойства к объекту и установив его значение действительно автоматически избежать амперсанд?
Основываясь на моих инстинктах и поддерживая эту ошибку, это было продуманное дизайнерское решение. Перегрузка свойств ($a-> d = 'Five & Six';) предназначена для того, чтобы "делать амперсанды для меня". Метод addChild предназначен для добавления метода "добавить то, что я говорю вам добавить". Итак, какое бы поведение вам ни понадобилось, SimpleXML может вас устраивать.
Скажем, у вас есть база данных с текстом, где все амперсанды уже сбежали. Для вас здесь не работает автоматическое экранирование. Это то, где вы будете использовать addChild. Или предположим, что вам нужно вставить объект в документ
$a = simplexml_load_string('<root></root>');
$a->b = 'This is a non-breaking space ';
$a->addChild('c','This is a non-breaking space ');
print $a->asXML();
Это то, что защищает PHP-разработчик в этой ошибке. Поведение addChild предназначено для предоставления "менее простой и надежной" поддержки, когда вам нужно вставить амперсанд в документ без его экранирования.
Конечно, это оставляет нам первую ситуацию, о которой я упоминал, метод addAttribute. Метод addAttribute позволяет избежать амперсандов. Итак, теперь мы можем указать несогласованность как
- Метод addAttribute ускоряет амперсанды
- Метод addChild не избегает амперсандов
- Такое поведение несколько противоречиво. Разумно, что пользователь будет ожидать, что методы на SimpleXML будут избегать вещей согласованным образом
Тогда это создает реальную проблему с SimpleXML api. Идеальная ситуация здесь была бы
- Перегрузка объектов на элементах объектов ускоряет амперсанды
- Перегрузка свойств объектов атрибутов ускоряет амперсанды
- Метод addChild не избегает амперсандов
- метод addAttribute не избегает амперсандов
Это невозможно, потому что SimpleXML не имеет понятия об объекте атрибута. Метод addAttribute является (как представляется,?) Единственным способом добавления атрибута. Из-за этого получается (кажется?) SimpleXML в неспособности создавать атрибуты с сущностями.
Все это показывает парадокс Simple XML. Идея этого API заключалась в том, чтобы обеспечить простой способ взаимодействия с чем-то, что оказывается сложным.
Команда могла бы добавить объект SimpleXMLAttribute, но это добавленный уровень сложности. Если вам нужна иерархия нескольких объектов, используйте DomDoument.
Команда могла добавлять флаги к методам addAttribute и addChild, но флаги делают API более сложным.
Настоящий урок здесь? Может быть, это просто и сложно, и простой в крайнем сроке еще сложнее. Я не знаю, было ли это так или нет, но с SimpleXML кажется, что кто-то начал с простой идеи (используйте перегрузку свойств, чтобы упростить создание XML-документов), а затем скорректировали с учетом запросов проблем/функций,
На самом деле, я считаю, что настоящим уроком является просто использование JSON;)
Ответ 2
Это мое решение, особенно это решает добавить несколько дочерних элементов с тем же именем тега
$job->addChild('industrycode')->{0} = $entry1;
$job->addChild('industrycode')->{0} = $entry2;
$job->addChild('industrycode')->{0} = $entry3;
Ответ 3
"Скажем, у вас есть база данных с текстом, где все амперсанды уже сбежали".
Если вы делаете это, вы делаете это неправильно. Данные должны храниться в его наиболее точной форме, а не обрабатываться для любого типа вывода, который вы в настоящее время используете. Это еще хуже, если вы фактически храните в базе данных blobs (действительный) HTML. Использование addChild() и захват данных снова приведет к уничтожению вашего HTML; никакая разумная библиотека не демонстрирует такую ужасную асимметрию.
addChild(), не кодирующий ваш текст для вас, полностью противоречит интуиции. Какой смысл в API, который не защищает вас от этого? Это похоже на json_encode() barfing, если вы используете двойную кавычку в одном из ваших значений.
В любом случае, чтобы ответить на исходный вопрос: Очевидно, я тоже думаю, что это нехорошее решение. Я думаю, что это согласуется с множеством решений по разработке PHP, которые должны выполнять кто-то идею о том, что "быстрее", а не быть правильным.
Ответ 4
Требование экранирования символов &
и <
содержится в разделе Character Data and Markup, а не в раздел "Нормализация атрибута", как сказано в предыдущем ответе.
Процитировать спецификацию XML.:
"Символ амперсанда (&) и левая угловая скобка (<) НЕ ДОЛЖНЫ отображаться в их литеральной форме, за исключением случаев, когда они используются в качестве разделителей разметки или в комментарии, инструкции обработки или секции CDATA. они необходимы в другом месте, они ДОЛЖНЫ быть экранированы с использованием либо числовых ссылок на символы, либо строк &
и <
соответственно"
Ответ 5
У Алана Шторма было хорошее описание проблемы, однако там было легко решить парадокс, который он описывает. Метод addChild() может иметь необязательный логический параметр, определяющий, следует ли автоматически выводить символы. Итак, я все еще убежден, что это просто (очень) плохой выбор дизайна.
Путаница усугубляется тем фактом, что документация для метода addChild() не содержит ссылок, поэтому проблема (хотя есть в обсуждении). Кроме того, метод избегает некоторых символов (а именно, меньше и больше знаков). Это приведет к заблуждению разработчиков, использующих метод, чтобы полагать, что он вообще избегает символов.
Ответ 6
Я считаю, что это вызвано "Нормализация атрибутов" , которое требует спецификация XML.