Подтвердить что ты не робот

Обоснование обработки 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 &amp; Four');
$a->d = 'Five & Six';

print($a->asXML());

Визуализирует:

<?xml version="1.0"?>
<a b="One &amp; Two">
    <c>Three &amp; Four</c>
    <d>Five &amp; Six</d>
</a>

На bugs.php.net они отвергают все представления об этом, говоря об этом. Почему это возможно? Кстати, в документах ничего не говорится об этом несоответствии экранировки текстовых значений SimpleXMLElement.

Может ли кто-нибудь убедить меня в том, что лучшее решение для дизайна API возможно?

4b9b3361

Ответ 1

Чтобы убедиться, что мы на одной странице, у вас есть три ситуации.

  1. Вставка амперсанда в атрибут с помощью addAttribute

  2. Вставка амперсанда в элемент с помощью addChild

  3. Вставка амперсанда в элемент путем перегрузки свойств

Это несоответствие между 2 и 3, которое вас сбило с толку. Почему AddChild автоматически не избежать амперсанд, в то время как при добавлении свойства к объекту и установив его значение действительно автоматически избежать амперсанд?

Основываясь на моих инстинктах и поддерживая эту ошибку, это было продуманное дизайнерское решение. Перегрузка свойств ($a-> d = 'Five & Six';) предназначена для того, чтобы "делать амперсанды для меня". Метод addChild предназначен для добавления метода "добавить то, что я говорю вам добавить". Итак, какое бы поведение вам ни понадобилось, SimpleXML может вас устраивать.

Скажем, у вас есть база данных с текстом, где все амперсанды уже сбежали. Для вас здесь не работает автоматическое экранирование. Это то, где вы будете использовать addChild. Или предположим, что вам нужно вставить объект в документ

$a = simplexml_load_string('<root></root>');
$a->b = 'This is a non-breaking space &nbsp;';
$a->addChild('c','This is a non-breaking space &nbsp;');    
print $a->asXML();

Это то, что защищает PHP-разработчик в этой ошибке. Поведение addChild предназначено для предоставления "менее простой и надежной" поддержки, когда вам нужно вставить амперсанд в документ без его экранирования.

Конечно, это оставляет нам первую ситуацию, о которой я упоминал, метод addAttribute. Метод addAttribute позволяет избежать амперсандов. Итак, теперь мы можем указать несогласованность как

  1. Метод addAttribute ускоряет амперсанды
  2. Метод addChild не избегает амперсандов
  3. Такое поведение несколько противоречиво. Разумно, что пользователь будет ожидать, что методы на SimpleXML будут избегать вещей согласованным образом

Тогда это создает реальную проблему с SimpleXML api. Идеальная ситуация здесь была бы

  1. Перегрузка объектов на элементах объектов ускоряет амперсанды
  2. Перегрузка свойств объектов атрибутов ускоряет амперсанды
  3. Метод addChild не избегает амперсандов
  4. метод 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. они необходимы в другом месте, они ДОЛЖНЫ быть экранированы с использованием либо числовых ссылок на символы, либо строк &amp; и &lt; соответственно"

Ответ 5

У Алана Шторма было хорошее описание проблемы, однако там было легко решить парадокс, который он описывает. Метод addChild() может иметь необязательный логический параметр, определяющий, следует ли автоматически выводить символы. Итак, я все еще убежден, что это просто (очень) плохой выбор дизайна.

Путаница усугубляется тем фактом, что документация для метода addChild() не содержит ссылок, поэтому проблема (хотя есть в обсуждении). Кроме того, метод избегает некоторых символов (а именно, меньше и больше знаков). Это приведет к заблуждению разработчиков, использующих метод, чтобы полагать, что он вообще избегает символов.