Обоснование обработки SimpleXMLElement текстовых значений в addChild и addAttribute - PullRequest
40 голосов
/ 16 февраля 2009

Разве это не противоречивое поведение? (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?

Ответы [ 6 ]

79 голосов
/ 17 февраля 2009

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

  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 будут избегать вещей согласованным образом

В этом случае выявляется реальная проблема с API SimpleXML. Идеальная ситуация здесь будет

  1. Перегрузка свойств на элементных объектах ускользает от амперсандов
  2. Перегрузка свойств в объектах атрибутов ускользает от амперсандов
  3. Метод addChild не экранирует амперсанды
  4. метод addAttribute не экранирует амперсанды

Это невозможно, потому что SimpleXML не имеет понятия объекта атрибута. Метод addAttribute является (кажется?) Единственным способом добавления атрибута. Из-за этого оказывается (кажется?) SimpleXML неспособным создавать атрибуты с сущностями.

Все это раскрывает парадокс Simple XML. Идея этого API состояла в том, чтобы предоставить простой способ взаимодействия с чем-то, что оказывается сложным.

Команда могла бы добавить объект SimpleXMLAttribute, но это дополнительный уровень сложности. Если вы хотите иерархию нескольких объектов, используйте DomDoument.

Команда могла бы добавить флаги в методы addAttribute и addChild, но флаги делают API более сложным.

Настоящий урок здесь? Может быть, это так просто, это сложно, а просто в срок еще сложнее. Я не знаю, так ли это было, но с SimpleXML кажется, что кто-то начал с простой идеи (используйте перегрузку свойств, чтобы упростить создание документов XML), а затем скорректировал ее по мере поступления запросов о проблемах / функциях .

На самом деле, я думаю, что настоящий урок здесь заключается в том, чтобы просто использовать JSON;)

16 голосов
/ 28 сентября 2012

Это моё решение, особенно это решает добавление нескольких потомков с одинаковым именем тега

$job->addChild('industrycode')->{0} = $entry1;
$job->addChild('industrycode')->{0} = $entry2;
$job->addChild('industrycode')->{0} = $entry3;
10 голосов
/ 15 апреля 2010

«Допустим, у вас была база данных с текстом, в которой все амперсанды уже были экранированы.»

Если вы делаете это, вы делаете это неправильно. Данные должны храниться в их наиболее точной форме, а не в соответствии с типом вывода, который вы используете в данный момент. Это даже хуже, если вы на самом деле сохраняете капли (действительного) HTML в базе данных. Использование addChild () и повторный захват данных уничтожат ваш HTML; ни одна разумная библиотека не обладает такой ужасной асимметрией.

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

Во всяком случае, чтобы ответить на оригинальный вопрос: Очевидно, я тоже думаю, что это не очень хорошее решение. Я думаю, что это согласуется со многими проектными решениями PHP, которые заключаются в том, чтобы воплотить в жизнь чье-то представление о том, что «быстрее», а не быть правильным.

7 голосов
/ 16 февраля 2009

Требование экранирования символов & и < приведено в разделе Символьные данные и разметка , а не в разделе Нормализация значений атрибутов, как указано в предыдущем ответе .

Цитировать спецификацию XML . :

"Символ амперсанда (&) и левая угловая скобка (<) НЕ ДОЛЖНЫ появляться в их буквальной форме, за исключением случаев, когда они используются в качестве разделителей разметки или в комментариях, инструкциях обработки или разделе CDATA. Если они в другом месте они ДОЛЖНЫ быть экранированы с использованием либо числовых ссылок на символы, либо строк <code>&amp; и &lt; соответственно "

5 голосов
/ 08 ноября 2011

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

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

0 голосов
/ 16 февраля 2009

Я полагаю, что это вызвано нормализацией значения атрибута , который требуется для спецификации XML.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...