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

Почему XML :: Simple обескуражен?

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

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

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

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

4b9b3361

Ответ 1

Реальная проблема заключается в том, что в первую очередь пытается сделать 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');

Ответ 2

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

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

[ { att => 'val', ..., content => [ 'content', 'content' ] }, ... ]
[ { att => 'val', ..., content => 'content' }, ... ]
[ { att => 'val', ..., }, ... ]
[ 'content', ... ]
{ 'id' => { att => 'val', ..., content => [ 'content', 'content' ] }, ... }
{ 'id' => { att => 'val', ..., content => 'content' }, ... }
{ 'id' => { att => 'val', ... }, ... }
{ 'id' => { content => [ 'content', 'content' ] }, ... }
{ 'id' => { content => 'content' }, ... }
{ att => 'val', ..., content => [ '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 does not 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) поддержку пространств имен и префиксов пространства имен.

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

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

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

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

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

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

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

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

  • Поддержка красивой печати.

Является ли XML :: Simple полезным?

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

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

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

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

Ответ 3

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

Я буду возражать и сказать, что 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.