Разве это не противоречивое поведение? (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"?> <ab="One & Two"> <c>Three & Four</c> <d>Five & Six</d> </a>
На bugs.php.net они отвергают все представления об этом, говоря, что это особенность. Почему это возможно? Кстати, в документах ничего не говорится об этом несоответствии экранировки текстовых значений SimpleXMLElement.
Может ли кто-нибудь убедить меня, что это лучшее решение для проектирования API?
Чтобы убедиться, что мы на одной странице, у вас есть три ситуации.
Вставка амперсанда в атрибут с помощью 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 позволяет избежать амперсандов. Итак, теперь мы можем указать несогласованность как
Тогда это создает реальную проблему с SimpleXML api. Идеальная ситуация здесь была бы
Это невозможно, потому что SimpleXML не имеет понятия об объекте атрибута. Метод addAttribute является (как представляется,?) Единственным способом добавления атрибута. Из-за этого получается (кажется?) SimpleXML в неспособности создавать атрибуты с сущностями.
Все это показывает парадокс Simple XML. Идея этого API заключалась в том, чтобы обеспечить простой способ взаимодействия с чем-то, что оказывается сложным.
Команда могла бы добавить объект SimpleXMLAttribute, но это дополнительный уровень сложности. Если вам нужна иерархия нескольких объектов, используйте DomDoument.
Команда могла добавлять флаги к методам addAttribute и addChild, но флаги делают API более сложным.
Настоящий урок здесь? Может быть, это просто, трудно, и простой в крайнем сроке еще сложнее. Я не знаю, было ли это так или нет, но с SimpleXML кажется, что кто-то начал с простой идеи (используйте перегрузку свойств, чтобы упростить создание XML-документов), а затем скорректировали с учетом запросов проблем / функций ,
На самом деле, я считаю, что настоящим уроком является просто использование JSON;)
Это мое решение, особенно это решает добавить несколько дочерних элементов с тем же именем тега
$job->addChild('industrycode')->{0} = $entry1; $job->addChild('industrycode')->{0} = $entry2; $job->addChild('industrycode')->{0} = $entry3;
«Скажем, у вас была база данных с текстом, где все амперсанды уже сбежали».
Если вы делаете это, вы делаете это неправильно. Данные должны храниться в его наиболее точной форме, а не обрабатываться для любого типа вывода, который вы в настоящее время используете. Это еще хуже, если вы фактически храните в базе данных blobs (действительный) HTML. Использование addChild () и захват данных снова приведет к уничтожению вашего HTML; никакая разумная библиотека не демонстрирует такую ужасную асимметрию.
addChild (), не кодирующий ваш текст для вас, полностью противоречит интуиции. Какой смысл в API, который не защищает вас от этого? Это похоже на json_encode () barfing, если вы используете двойную кавычку в одном из ваших значений.
В любом случае, чтобы ответить на исходный вопрос: Очевидно, я тоже считаю, что это нехорошее решение. Я действительно думаю, что это согласуется с множеством дизайнерских решений PHP, которые должны выполнять чью-то идею о том, что «быстрее», а не быть правильным.
Требование об экранировании символов &
и <
указано в разделе « Символьные данные и разметка», а не в разделе «Нормализация атрибутов», как указано в предыдущем ответе .
Процитировать XML Spec . :
«Символ амперсанда (&) и левая угловая скобка (<) НЕ ДОЛЖНЫ появляться в их литеральной форме, за исключением случаев, когда они используются в качестве разделителей разметки или в комментарии, инструкции обработки или секции CDATA. Если они необходимы в другом месте, они ДОЛЖНЫ быть экранированы с использованием либо числовых символьных ссылок, либо строк &
и <
соответственно "
У Алана Шторма было хорошее описание проблемы, но есть легкое решение парадокса, которое он описывает. Метод addChild () может иметь необязательный логический параметр, определяющий, следует ли автоматически выводить символы. Итак, я все еще убежден, что это просто (очень) плохой выбор дизайна.
Путаница усугубляется тем фактом, что документация для метода addChild () не делает никакой ссылки, поэтому проблема (хотя есть в обсуждении). Кроме того, метод избегает некоторых символов (а именно, меньше и больше знаков). Это приведет к заблуждению разработчиков, использующих метод, чтобы полагать, что он избегает символов в целом.
Я считаю, что это вызвано нормализацией атрибутов, требуемой спецификацией XML.