Парсинг XML CDATA с [закрытым] PHP

Это мне походит на довольно типичную проблему, с которой юниор промежуточным разработчикам склонен сталкиваться в какой-то момент: они или не знают или не доверяют контрактам, они участвуют в и оборонительно сверхпроверяют на пустые указатели. Кроме того, при записи их собственного кода, они имеют тенденцию полагаться на возврат, аннулирует для указания на что-то таким образом требование, чтобы вызывающая сторона проверила на пустые указатели.

Для помещения этого иначе существует два экземпляра, где пустая проверка подходит:

  1. , Где пустой указатель является допустимым ответом с точки зрения контракта; и

  2. , Где это не допустимый ответ.

(2) легко. Или используйте assert операторы (утверждения) или позвольте отказ (например, NullPointerException). Утверждения являются высоко недогруженной опцией Java, которая была добавлена в 1,4. Синтаксис:

assert 

или

assert  : 

то, где булево выражение и , является объектом, чей toString() вывод метода будет включен в ошибку.

assert оператор бросает Error (AssertionError), если условие не верно. По умолчанию Java игнорирует утверждения. Можно включить утверждения путем передачи опции -ea JVM. Можно включить и отключить утверждения для отдельных классов и пакетов. Это означает, что можно проверить код с утверждениями при разработке и тестировании, и отключить их в продуктивной среде, хотя мое тестирование не показало рядом ни с каким влиянием производительности от утверждений.

Не утверждения использования в этом случае в порядке, потому что код просто перестанет работать, который является тем, что произойдет, если Вы будете использовать утверждения. Единственная разница - то, что с утверждениями это могло бы произойти раньше, в более - значимый путь и возможно с дополнительной информацией, которая может помочь Вам выяснить, почему это произошло, если Вы не ожидали его.

(1) немного более твердо. Если Вы не имеете никакого контроля над кодом, Вы звоните тогда, Вы застреваете. Если пустой указатель является допустимым ответом, необходимо проверить на него.

, Если это - код, которым Вы действительно управляете, однако (и это часто имеет место), тогда это - другая история. Избегайте использования аннулирует как ответ. С методами, которые возвращают наборы, это легко: возвратите пустые наборы (или массивы) вместо пустых указателей в значительной степени все время.

С ненаборами это могло бы быть более твердо. Рассмотрите это как пример: если у Вас есть эти интерфейсы:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

, где Синтаксический анализатор берет необработанный ввод данных пользователем и находит, что что-то делает, возможно, при реализации интерфейса командной строки для чего-то. Теперь Вы могли бы сделать контракт, что он возвращает пустой указатель, при отсутствии соответствующих мер. Это приводит пустой указатель, проверяющий, что Вы говорите о.

альтернативное решение никогда не состоит в том, чтобы возвращать пустой указатель и вместо этого использовать шаблон Несуществующего объекта :

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

Сравните:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

к [1 136]

ParserFactory.getParser().findAction(someInput).doSomething();

, который является намного лучшим дизайном, потому что он приводит к более краткому коду.

Однако возможно, для findAction () метод совершенно уместно выдать Исключение со значимым сообщением об ошибке - особенно в этом случае, где Вы полагаетесь на ввод данных пользователем. Для findAction метода было бы намного лучше выдать Исключение, чем для вызывающего метода аварийно завершиться с простым NullPointerException без объяснения.

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

Или если Вы думаете, механизм попытки/выгоды слишком ужасен, а не Не Сделайте Ничего, что Ваше действие по умолчанию должно предоставить обратную связь пользователю.

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

6
задан Helen Neely 7 August 2009 в 20:21
поделиться

1 ответ

Просто из любопытства, после получения вашего XML (надеюсь, я не уничтожил его в процессе - я посмотрю, смогу ли я отредактировать OP, чтобы исправить это) :

  • вы преобразовали описание в строку?


Я имею в виду, что вы могли бы использовать это:

$xml = simplexml_load_string($str);
foreach ($xml->channel->item as $item) {
    var_dump($item->description);
}

Но это даст вам только следующее:

object(SimpleXMLElement)[5]
object(SimpleXMLElement)[3]

Что не так уж хорошо ...


Вам нужно преобразовать данные в строку, например:

$xml = simplexml_load_string($str);
foreach ($xml->channel->item as $item) {
    var_dump((string)$item->description);
}

И вы получите описания:

string '

This is one of the content that I need printed on the screen, but nothing is happening. Please, please...output something... <br /><br /> <b>Showing</b>: 2 weeks<br /> <b>Starting On</b>: August 7, 2009 <br /> <b>Posted On</b>: August 7, 2009 <br />
<a href="http://www.mysite.com">click to view</a> 
            ' (length=329)

string '

Another content...This is another of the content that I need printed on the screen, but nothing is happening. Please, please...output something... <br /><br /> <b>Showing</b>: 2 weeks<br /> Starting On: August 7, 2009 <br /> <b>Posted On</b>: August 7, 2009
; 
               ' (length=303)

(Использование trim для них может оказаться полезным, кстати, если ваш XML имеет отступы)


Иначе ... Что ж, нам, вероятно, понадобится ваш php-код (по крайней мере, было бы полезно узнать, как вы попадаете в тег description ; -) )


ИЗМЕНИТЬ

Спасибо за отформатированный XML!

Если я перейду на pastebin, в текстовое поле внизу страницы,в начале XML есть пробел перед

Если он есть в ваших настоящих XML-данных, он будет быть источником проблемы: это недопустимый XMl (объявление XML должно быть первым элементом в данных XML).
Вы получите такую ​​ошибку:

Warning: simplexml_load_string() [function.simplexml-load-string]: Entity: line 1: parser error : XML declaration allowed only at the start of the document

Вы можете это проверить?
И, если проблема здесь, вы должны активировать error_reporting и display_errors ;-) Это поможет!


ИЗМЕНИТЬ, просмотрев файл PHP:

В вашем цикле for вы делаете это, чтобы получить данные описания:

$item_desc = $x->item($i)->getElementsByTagName('description')->item(0)->childNodes->item(0)->nodeValue;

description не содержит дочерних узлов, я бы сказал; как насчет прямого использования nodeValue?
Вот так:

$item_desc = $x->item($i)->getElementsByTagName('description')->item(0)->nodeValue;

Похоже, этот способ лучше работает: -)

В качестве примечания, я полагаю, вы могли бы сделать то же самое для других тегов; например, похоже, это тоже работает:

$item_title=$x->item($i)->getElementsByTagName('title')->item(0)->nodeValue;
$item_link=$x->item($i)->getElementsByTagName('link')->item(0)->nodeValue;

Что это дает?


Еще одно РЕДАКТИРОВАНИЕ: и вот код, который я, вероятно, использовал бы:

$xmlDoc = new DOMDocument();
$xmlDoc->loadXML($str);         // I changed that because I have the XML data in a string

//get elements from "<channel>"
$channel = $xmlDoc->getElementsByTagName('channel')->item(0);
$channel_title = $channel->getElementsByTagName('title')->item(0)->nodeValue;
$channel_link = $channel->getElementsByTagName('link')->item(0)->nodeValue;
$channel_desc = $channel->getElementsByTagName('description')->item(0)->nodeValue;

//output elements from "<channel>"
echo "<p><a href='" . $channel_link . "'>" . $channel_title . "</a>";
echo "<br />";
echo $channel_desc . "</p>";

//get and output "<item>" elements
$x = $xmlDoc->getElementsByTagName('item');
for ($i=0 ; $i<=1 ; $i++) {
    $item_title = $x->item($i)->getElementsByTagName('title')->item(0)->nodeValue;
    $item_link = $x->item($i)->getElementsByTagName('link')->item(0)->nodeValue;
    $item_desc = $x->item($i)->getElementsByTagName('description')->item(0)->nodeValue;
    echo ("<p><a href='" . $item_link
    . "'>" . $item_title . "</a>");
    echo ("<br />");
    echo ($item_desc . "</p>");
    echo' <p />';
}

Обратите внимание, что у меня есть данные XML в строке, и я не нужно получать его по URL-адресу, поэтому я использую метод loadXML , а не load .

Основное отличие состоит в том, что я удалил некоторые обращения к дочерним узлам, которые Я чувствую, что в этом нет необходимости.
Вам это кажется нормальным?

17
ответ дан 8 December 2019 в 13:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: