首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么不鼓励使用XML::Simple?

为什么不鼓励使用XML::Simple?
EN

Stack Overflow用户
提问于 2015-10-22 03:36:44
回答 3查看 12.4K关注 0票数 58

来自XML::Simple的文档

不鼓励在新代码中使用此模块。还可以使用其他模块,它们提供了更直观、更一致的界面。特别是,强烈推荐使用XML::LibXML。

这个模块的主要问题是大量的选项和这些选项交互的任意方式-通常会产生意想不到的结果。

有没有人能为我解释一下这其中的主要原因是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-10-22 03:36:44

真正的问题是,XML::Simple主要尝试做的是获取XML,并将其表示为perl数据结构。

perldata中您一定知道,可用的两个关键数据结构是hasharray

  • 数组是有序标量。
  • 哈希是无序的键值对。

而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};

注意你是如何获得一个“子”节点的,在它下面有一个“内容”节点,这不是因为它是...内容。

但是要访问第一个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'
                                   }
                                 ]
                      }
                    ]
        };

这将为您提供一致性,因为您将不再有不同于多节点的单节点元素处理方式。

但你仍然:

  • 有一个5个引用的深度树来获取一个值。

例如:

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

您仍然可以将contentchild散列元素视为属性,并且因为散列是无序的,所以不能重构输入。因此,基本上,您必须解析它,然后通过Dumper运行它,以确定您需要查找的位置。

但是对于xpath查询,您可以通过以下命令到达该节点:

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

XML::Simple中没有得到在XML::Twig中做的事情(我假设是XML::LibXML,但我对它不太了解):

  • xpath支持。xpath是一种表示到节点的路径的XML方式。所以你可以用get_xpath('//child')在上面的代码中“找到”一个节点。您甚至可以在类似xpathget_xpath('//another_child[@different_att]')中使用属性,它将准确地选择您想要的属性。(您也可以迭代匹配项)。
  • cutpaste用于移动图元around
  • parsefile_inplace,以允许您通过在位编辑来修改XML
  • pretty_print选项,用于格式化XML
  • twig_handlerspurge -允许您处理非常大的XML,而不必将其全部加载到内存中。如果你真的想让它向后兼容XML::Simple,那就使用
  • simplify
  • 代码通常比尝试遵循对散列和数组的菊花链引用要简单得多,因为结构上的根本差异永远不可能始终如一地完成。

它也可以广泛使用-很容易从CPAN下载,并以可安装包的形式在许多操作系统上分发。(遗憾的是,这不是默认安装。还没有)

请参阅:XML::Twig quick reference

为了便于比较:

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');
票数 54
EN

Stack Overflow用户

发布于 2015-10-22 12:37:19

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 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强加了许多限制,并且它缺乏共同的特性

它对于生成是完全无用的。即使有了ForceArray => 1, ForceContent => 1, KeyAttr => [], KeepRoot => 1,对于命名空间和命名空间解析器后端(例如,XML::Parser)的支持有限(使用XML::SAX后端)或不支持(使用XML::解析器后端)。controlled.

  • It prefixes.
  • Some后端(例如,XML::解析器)无法处理不基于ASCII码的编码(例如,UTF-16le).
  • An
  • 不能具有具有相同name.H217<的子元素和属性/code>
  • 无法创建带注释的

文档。

忽略前面提到的主要问题,XML::Simple仍然可以在具有这些限制的情况下使用。但是,为什么要麻烦地检查XML::Simple是否可以处理您的文档格式,并冒着以后必须切换到另一个解析器的风险呢?您可以简单地从一开始就为所有文档使用更好的解析器。

其他一些解析器不仅不会让您受到这些限制,它们还提供了许多其他有用的特性。以下是XML::Simple可能没有的一些功能:

  • 速度。XML::Simple非常慢,特别是当您使用XML::Parser之外的后端时。我说的是比其他parsers.
  • XPath选择器慢几个数量级,或者similar.
  • Support比非常大的documents.
  • Support慢几个数量级,打印很漂亮。

XML::Simple有用吗?

对于XML::Simple来说,唯一最简单的格式是没有可选元素的格式。我有过无数使用XML格式的经验,但从来没有遇到过这样的格式。

仅这种脆弱性和复杂性就足以保证远离XML::Simple,但还有其他原因。

替代方案

我使用XML::LibXML。它是一个速度极快、功能齐全的解析器。如果需要处理内存不能容纳的文档,我会使用XML::LibXML::Reader (及其copyCurrentNode(1))或XML::Twig (使用twig_roots)。

票数 33
EN

Stack Overflow用户

发布于 2015-10-23 00:23:46

我不同意文档的观点

我不同意,说XML::Simple就是这样的..很简单。而且,对我来说,使用它一直都很容易,也很有趣。用你收到的输入来测试它。只要输入没有改变,你就是好的。抱怨使用XML::Simple的人也抱怨使用JSON::Syck序列化驼鹿。这些文档是错误的,因为它们考虑的是正确性而不是效率。如果你只关心以下几点,那你就不错了:

  • 不丢弃data
  • 构建为提供的格式,而不是抽象架构

如果你正在制作一个抽象解析器,它不是由应用程序定义的,而是由规范定义的,我会使用其他的东西。我曾经在一家公司工作过,我们不得不接受300种不同的XML模式,但没有一种模式有规范。XML::Simple轻松地完成了这项工作。其他选项将要求我们实际雇用某人来完成这项工作。每个人都认为XML是以严格的、包罗万象的格式发送的,如果您编写一个解析器,那么您就是好的。如果是这样的话,就不要使用XML::Simple。在JSON之前,XML只是一种从一种语言到另一种语言的“转储并遍历”格式。人们实际上使用像XML::Dumper这样的东西。实际上,没有人知道输出了什么。处理这种情况时,XML::Simple非常棒!理智的人仍然会在没有规范的情况下转储到JSON来完成同样的事情。这就是世界的运转方式。

想要读入数据,而不用担心格式吗?想要遍历Perl结构而不是XML?Go XML::Simple

延伸一下..。

同样,对于大多数应用程序,JSON::Syck足以将其转储并遍历。不过,如果你要发送给很多人,我强烈建议你不要做一个愚蠢的喷嘴,而是制定一个你可以输出的规范。但是你知道吗..。有时你会接到一个你不想和他交谈的人的电话,他想要你通常不会导出的数据。如果他们想要XML,那就再多收500美元,然后启动你的XML::Dumper

带走

它可能并不完美,但XML::Simple的效率非常高。在这个竞技场上节省的每一个小时,你都有可能花在一个更有用的竞技场上。这是一个现实世界的考虑因素。

其他答案

听着,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]将抛出一个错误。不管怎样,那只是perl而已。这与XML::Simple imho有关。而且,我承认XML::Simple不适合按照规范进行构建。显示数据,我就可以用XML::Simple访问它。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33267765

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档