Почему XML :: Simple не рекомендуется?

52

Из документации XML::Simple:

Использование этого модуля в новом коде не рекомендуется. Доступны и другие модули, которые обеспечивают более простые и последовательные интерфейсы. В частности, настоятельно рекомендуется использовать XML:: LibXML.

Основными проблемами с этим модулем являются большое количество опций и произвольные способы взаимодействия этих параметров - часто с неожиданными результатами.

Может кто-нибудь уточнить для меня, каковы основные причины этого?

  • 1
    Также может быть интересно услышать плюсы / минусы для metacpan.org/pod/XML::Fast
  • 0
    Вы создаете статью базы знаний, на которую вы можете ссылаться в своем стремлении убить XML :: Simple? : D
Показать ещё 8 комментариев
Теги:
xml-simple

3 ответа

50
Лучший ответ

Реальная проблема заключается в том, что в первую очередь пытается сделать XML::Simple, это взять XML и представить его как структуру данных perl.

Как вы, несомненно, знаете из perldata две доступные структуры данных: hash и array.

  • Массивы - это упорядоченные скаляры.
  • хеши - это неупорядоченные пары ключ-значение.

И XML не работает. Он имеет элементы, которые:

  • не имеет однозначного имени (что означает, что хеши не подходят).
  • .... но "упорядочены" внутри файла.
  • могут иметь атрибуты (которые вы могли бы вставить в хэш)
  • может иметь контент (но не может, но может быть унарным тегом)
  • могут иметь детей (любой глубины)

И эти вещи не отображаются непосредственно в доступные структуры данных perl - на упрощенном уровне может возникнуть вложенный хеш хешей, но он не может справиться с элементами с дублируемыми именами. Также вы не можете легко различать атрибуты и дочерние узлы.

Итак, XML::Simple пытается угадать на основе содержимого XML и принимает "подсказки" из различных параметров параметров, а затем, когда вы пытаетесь вывести контент, он (пытается) применить тот же процесс в обратном порядке.

В результате, для чего угодно, кроме самого простого XML, в лучшем случае он становится громоздким или теряет данные в худшем случае.

Рассмотрим:

<xml>
   <parent>
       <child att="some_att">content</child>
   </parent>
   <another_node>
       <another_child some_att="a value" />
       <another_child different_att="different_value">more content</another_child>
   </another_node>
</xml>

Это - при анализе через XML::Simple дает вам:

$VAR1 = {
          'parent' => {
                      'child' => {
                                 'att' => 'some_att',
                                 'content' => 'content'
                               }
                    },
          'another_node' => {
                            'another_child' => [
                                               {
                                                 'some_att' => 'a value'
                                               },
                                               {
                                                 'different_att' => 'different_value',
                                                 'content' => 'more content'
                                               }
                                             ]
                          }
        };

Примечание. Теперь у вас есть под parent - только анонимные хеши, но под another_node у вас есть массив анонимных хэшей.

Итак, чтобы получить доступ к содержимому child:

my $child = $xml -> {parent} -> {child} -> {content};

Обратите внимание, что у вас есть "дочерний" node, под ним "контент" node, который не потому, что он... контент.

Но для доступа к содержимому под первым элементом another_child:

 my $another_child = $xml -> {another_node} -> {another_child} -> [0] -> {content};

Обратите внимание, что - из-за наличия нескольких элементов <another_node> XML был проанализирован в массив, где он не был с одним. (Если у вас есть элемент под названием content под ним, то вы в конечном итоге еще что-то еще). Вы можете изменить это, используя ForceArray, но затем вы получите хэш массивов хэшей массивов хешей массивов - хотя это по крайней мере непротиворечиво в нем обработка дочерних элементов. Изменить: Обратите внимание, что после обсуждения - это плохой дефолт, а не ошибка с XML:: Simple.

Вы должны установить:

ForceArray => 1, KeyAttr => [], ForceContent => 1

Если вы примените это к XML, как указано выше, вы получите вместо этого:

$VAR1 = {
          'another_node' => [
                            {
                              'another_child' => [
                                                 {
                                                   'some_att' => 'a value'
                                                 },
                                                 {
                                                   'different_att' => 'different_value',
                                                   'content' => 'more content'
                                                 }
                                               ]
                            }
                          ],
          'parent' => [
                      {
                        'child' => [
                                   {
                                     'att' => 'some_att',
                                     'content' => 'content'
                                   }
                                 ]
                      }
                    ]
        };

Это даст вам согласованность, потому что вы больше не будете иметь отдельные элементы node, которые обрабатывают по-разному с помощью multi- node.

Но вы все еще:

  • У вас есть 5 опорных глубинных деревьев, чтобы получить значение.

Например:

print $xml -> {parent} -> [0] -> {child} -> [0] -> {content};

У вас все еще есть content и child хэш-элементы, обработанные так, как если бы они были атрибутами, а поскольку хеши неупорядочены, вы просто не можете восстановить вход. Итак, в основном, вам нужно разобрать его, а затем запустить через Dumper, чтобы выяснить, где вам нужно искать.

Но с запросом xpath вы получите node с помощью:

findnodes("/xml/parent/child"); 

То, что вы не получаете в XML::Simple, которое вы делаете в XML::Twig (и я предполагаю XML::LibXML, но я знаю его менее хорошо):

  • xpath поддержка. xpath - это XML-способ выражения пути к node. Таким образом, вы можете "найти" node в приведенном выше примере с помощью get_xpath('//child'). Вы даже можете использовать атрибуты в xpath - как get_xpath('//another_child[@different_att]'), который будет выбирать именно тот, который вы хотите. (Вы также можете перебирать спички).
  • cut и paste для перемещения элементов вокруг
  • parsefile_inplace, чтобы вы могли изменить XML с помощью редактирования.
  • pretty_print, чтобы форматировать XML.
  • twig_handlers и purge - который позволяет обрабатывать действительно большой XML без необходимости загружать все это в память.
  • simplify, если вы действительно должны сделать его обратно совместимым с XML::Simple.
  • код обычно проще, чем пытаться следовать цепочкам ссылок на хеши и массивы, которые никогда не могут выполняться последовательно из-за фундаментальных различий в структуре.

Он также широко доступен - легко загружается с CPAN и распространяется как устанавливаемый пакет во многих операционных системах. (К сожалению, это не стандартная установка.)

Смотрите: XML:: Быстрая ссылка

Для сравнения:

my $xml = XMLin( \*DATA, ForceArray => 1, KeyAttr => [], ForceContent => 1 );

print Dumper $xml;
print $xml ->{parent}->[0]->{child}->[0]->{content};

Vs.

my $twig = XML::Twig->parse( \*DATA );
print $twig ->get_xpath( '/xml/parent/child', 0 )->text;
print $twig ->root->first_child('parent')->first_child_text('child');
  • 4
    К сожалению, это не установка по умолчанию. Если под «установкой по умолчанию» вы подразумеваете основной модуль, то да, я согласен с вами. Но если вместо этого вы имеете в виду пакет с дистрибутивом Perl, Strawberry Perl включает предустановленные модули XML (XML :: LibXML, XML :: Parser, XML :: Twig и т. Д.), По крайней мере, с мая 2014 года , возможно, дольше.
  • 7
    IMO это в значительной степени сводится к тому, что ForceArray должен был по умолчанию установить значение 1 (и это нельзя изменить, не нарушая большинство существующих применений). Если XML :: Simple отвечает вашим потребностям, нет никаких причин не использовать его.
Показать ещё 3 комментария
33

XML:: Simple - это самый сложный XML-анализатор, доступный

Основная проблема с XML:: Simple заключается в том, что результирующая структура чрезвычайно сложна для правильной навигации. $ele->{ele_name} может возвращать любое из следующего (даже для элементов, которые следуют той же спецификации):

[ { att => 'val', ..., content => 'content' }, ... ]
[ { att => 'val', ..., }, ... ]
[ 'content', ... ]
{ 'id' => { att => 'val', ..., content => 'content' }, ... }
{ 'id' => { att => 'val', ... }, ... }
{ 'id' => { content => 'content' }, ... }
{ att => 'val', ..., content => 'content' }
{ att => 'val', ..., }
'content'

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

Параметры для создания более правильного дерева не соответствуют

Вы можете использовать следующие параметры для создания более регулярного дерева:

ForceArray => 1, KeyAttr => [], ForceContent => 1

Но даже с этими параметрами требуется много проверок для извлечения информации из дерева. Например, получение узлов /root/eles/ele из документа является общей операцией, которая должна быть тривиальной для выполнения, но при использовании XML:: Simple требуется следующее:

# Requires: ForceArray => 1, KeyAttr => [], ForceContent => 1, KeepRoot => 0
# Assumes the format doesn't allow for more than one /root/eles.
# The format wouldn't be supported if it allowed /root to have an attr named eles.
# The format wouldn't be supported if it allowed /root/eles to have an attr named ele.
my @eles;
if ($doc->{eles} && $doc->{eles}[0]{ele}) {
    @eles = @{ $doc->{eles}[0]{ele} };
}

В другом парсере можно использовать следующее:

my @eles = $doc->findnodes('/root/eles/ele');

XML:: Simple накладывает многочисленные ограничения, и в нем отсутствуют общие функции

  • Это совершенно бесполезно для создания XML. Даже с ForceArray => 1, ForceContent => 1, KeyAttr => [], KeepRoot => 1 имеется слишком много деталей, которые невозможно контролировать.

  • Он не сохраняет относительный порядок детей с разными именами.

  • Он ограничен (с бэкэндом XML:: SAX) или нет (с поддержкой XML:: Parser) для пространств имен и префиксов пространства имен.

  • Он не может обрабатывать элементы как с текстом, так и с элементами в виде дочерних элементов (что означает, что он не может обрабатывать XHTML, среди прочих).

  • Некоторые серверы (например, XML:: Parser) не могут обрабатывать кодировки, не основанные на ASCII (например, UTF-16le).

  • Элемент не может иметь дочерний элемент и атрибут с тем же именем.

  • Он не может создавать XML-документы с комментариями.

Игнорируя основные проблемы, о которых упоминалось ранее, XML:: Simple все еще можно использовать с этими ограничениями. Но почему вы столкнулись с проблемой проверки того, может ли XML:: Simple обрабатывать ваш формат документа и рискнуть переключиться на другой парсер позже? Вы можете просто использовать лучший парсер для всех ваших документов с самого начала.

Мало того, что некоторые другие синтаксические анализаторы не подвергают вас этим ограничениям, они дополнительно предоставляют множество других полезных функций. Ниже перечислены некоторые функции, которые могут иметь, что XML:: Simple не делает:

  • Скорость. XML:: Simple чрезвычайно медленный, особенно если вы используете бэкэнд, отличный от XML:: Parser. Я говорю на порядки медленнее, чем другие парсеры.

  • Селектора XPath или аналогичные.

  • Поддержка чрезвычайно больших документов.

  • Поддержка печати. ​​

Является ли XML:: простым когда-либо полезным?

Единственный формат, для которого XML:: Simple является самым простым, - это тот, где ни один элемент не является обязательным. У меня был опыт работы с бесчисленными форматами XML, и я никогда не сталкивался с таким форматом.

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

Альтернативы

Я использую XML:: LibXML. Это чрезвычайно быстрый, полнофункциональный синтаксический анализатор. Если мне когда-либо понадобилось обрабатывать документы, которые не вписывались в память, я бы использовал XML:: LibXML:: Reader (и его copyCurrentNode(1)) или XML:: Twig (используя twig_roots).

  • 0
    XML :: TreePP, как мне кажется, не имеет волшебной догадки XML :: Simple имеет. Но вы можете сказать это, как вести себя точно. С ним также проще работать, чем с XML :: LibXML и его семейством. Для создания XML я бы использовал XML :: TreePP, для синтаксического анализа внешнего XML-содержимого, возможно, XML :: LibXML, если у вас гигантские XML-файлы и скорость - это проблема.
  • 1
    @nicomen, при условии, что вы используете $tpp->set( force_array => [ '*' ] ); тебе нужны хотя бы my @eles; if ($doc->{root} && $doc->{root}[0]{eles} && $doc->{root}[0]{eles}[0]{ele}) { @eles = @{ $doc->{root}[0]{eles}[0]{ele} } } чтобы получить узлы /root/eles/ele , и предполагается, что не может быть нескольких узлов eles . Это ничем не отличается от оптимально настроенного XML :: Simple. (Это намного хуже без force_array => [ '*' ] .)
Показать ещё 6 комментариев
4

Я не согласен с документами

Я буду возражать и сказать, что XML::Simple - это просто.. просто. И мне всегда было легко и приятно пользоваться. Проверьте его с помощью ввода, который вы получаете. Пока вход не меняется, вы в порядке. Те же люди, которые жалуются на использование XML::Simple, жалуются на использование JSON::Syck для сериализации Moose. Документы ошибочны, поскольку они учитывают правильность эффективности. Если вас беспокоит только следующее, вы хорошо:

  • не выбрасывать данные
  • построение с предоставленным форматом, а не абстрактная схема

Если вы создаете абстрактный парсер, который не определен приложением, а по спецификации, я бы использовал что-то еще. Я работал в компании один раз, и нам пришлось принять 300 различных схем XML, ни один из которых не имел спецификации. XML::Simple легко выполнил работу. Другие варианты потребовали бы, чтобы мы наняли кого-то, чтобы выполнить работу. Все думают, что XML - это то, что отправлено в жестком всеохватывающем специфицированном формате, так что если вы напишете один парсер, вы добры. Если в этом случае не используется XML::Simple. XML, до JSON, был всего лишь "дампом этого и гуляющего" формата с одного языка на другой. Люди действительно использовали такие вещи, как XML::Dumper. Никто не знал, что вышло. Работа с этим сценарием XML::Simple is greattt! Сэйнские люди все еще сбрасывают JSON без спецификации для достижения того же самого. Это как работает мир.

Хотите прочитать данные и не беспокоиться о формате? Хотите пересечь структуры Perl, а не возможности XML? Перейти XML::Simple.

По расширению...

Аналогично, для большинства приложений JSON::Syck достаточно сбрасывать это и ходить. Хотя, если вы отправляете много людей, я бы предложил вам не использовать сопло для душа и делать спецификацию, на которую вы экспортируете. Но, вы знаете, что.. Когда-нибудь вы получите звонок от кого-то, с кем вы не хотите говорить, кто хочет, чтобы его данные не экспортировались обычно. И вы собираетесь пропустить его через JSON::Syck voodoo и позволить им беспокоиться об этом. Если они хотят XML? Зарядите их еще на 500 долларов и запустите ole XML::Dumper.

Уберите

Он может быть менее совершенным, но XML::Simple эффективен. Каждый час, сэкономленный на этой арене, вы можете потратить на более полезную арену. Это реальное мировоззрение.

Другие ответы

У Look XPath есть некоторые проблемы. Каждый ответ здесь сводится к предпочтению XPath над Perl. Это здорово. Если вы предпочитаете использовать стандартизованный XML-язык для доступа к вашему XML, имейте это в виду!

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

var $xml = [ { foo => 1 } ];  ## Always w/ ForceArray.

var $xml = { foo => 1 };

Получение значения foo здесь в этих двух контекстах может быть сложным. XML::Simple знает это и то, почему вы можете заставить первого. Однако, даже с ForceArray, если элемент отсутствует, вы будете выкидывать ошибку.

var $xml = { bar => [ { foo => 1 } ] };

теперь, если bar не является обязательным, вы получите доступ к нему $xml->{bar}[0]{foo}, а @{$xml->{bar}}[0] выдаст ошибку. Во всяком случае, это просто перл. Это связано с XML::Simple imho. И я признал, что XML::Simple не подходит для построения спецификации. Покажите мне данные, и я могу получить к нему доступ с помощью XML:: Simple.

  • 0
    Комментарии не для расширенного обсуждения; этот разговор был перенесен в чат .
  • 0
    Давайте продолжим эту дискуссию в чате .
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню