Sob*_*que 55 xml perl xml-simple
来自以下文件XML::Simple:
不鼓励在新代码中使用此模块.其他模块可用,提供更直接和一致的接口.特别强烈建议使用XML :: LibXML.
该模块的主要问题是大量选项以及这些选项交互的任意方式 - 通常会产生意外结果.
有人可以为我澄清一下这主要原因是什么?
Sob*_*que 54
真正的问题是,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>
Run Code Online (Sandbox Code Playgroud)
这 - 解析时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'
}
]
}
};
Run Code Online (Sandbox Code Playgroud)
注意 - 现在你有一些parent- 只是匿名哈希,但another_node你有一个匿名哈希数组.
所以为了访问以下内容child:
my $child = $xml -> {parent} -> {child} -> {content};
Run Code Online (Sandbox Code Playgroud)
请注意你有一个'子'节点,它下面有一个'内容'节点,这不是因为它是......内容.
但要访问第一个another_child元素下面的内容:
my $another_child = $xml -> {another_node} -> {another_child} -> [0] -> {content};
Run Code Online (Sandbox Code Playgroud)
请注意 - 由于具有多个<another_node>元素,XML已被解析为数组,而不是单个数组.(如果你确实有一个content在它下面调用的元素,那么你最终会得到其他东西).你可以通过使用来改变它,ForceArray但最后你会得到一个哈希数组哈希数组的哈希值 - 尽管它在处理子元素时至少是一致的.编辑:注意,下面的讨论 - 这是一个错误的默认值,而不是XML :: Simple的缺陷.
你应该设置:
ForceArray => 1, KeyAttr => [], ForceContent => 1
Run Code Online (Sandbox Code Playgroud)
如果您将此应用于上述XML,则会得到:
$VAR1 = {
'another_node' => [
{
'another_child' => [
{
'some_att' => 'a value'
},
{
'different_att' => 'different_value',
'content' => 'more content'
}
]
}
],
'parent' => [
{
'child' => [
{
'att' => 'some_att',
'content' => 'content'
}
]
}
]
};
Run Code Online (Sandbox Code Playgroud)
这将为您提供一致性,因为您将不再具有与多节点不同的单节点元素处理.
但你还是:
例如:
print $xml -> {parent} -> [0] -> {child} -> [0] -> {content};
Run Code Online (Sandbox Code Playgroud)
你还有content和child散列元素处理,如果他们的属性,而且由于哈希是无序的,你根本无法重建的投入.所以基本上,你必须解析它,然后运行它Dumper来找出你需要看的地方.
但是通过xpath查询,您可以使用以下命令获取该节点:
findnodes("/xml/parent/child");
Run Code Online (Sandbox Code Playgroud)
你没有得到的XML::Simple东西XML::Twig(我猜想XML::LibXML但我知道的不太好):
xpath支持.xpath是表示节点路径的XML方式.所以你可以在上面找到一个节点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 :: Twig快速参考
为了比较:
my $xml = XMLin( \*DATA, ForceArray => 1, KeyAttr => [], ForceContent => 1 );
print Dumper $xml;
print $xml ->{parent}->[0]->{child}->[0]->{content};
Run Code Online (Sandbox Code Playgroud)
比.
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');
Run Code Online (Sandbox Code Playgroud)
ike*_*ami 32
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'
Run Code Online (Sandbox Code Playgroud)
这意味着您必须执行各种检查以查看您实际获得的内容.但这种复杂性使得开发人员做出了非常糟糕的假设.
您可以使用以下选项创建更常规的树:
ForceArray => 1, KeyAttr => [], ForceContent => 1
Run Code Online (Sandbox Code Playgroud)
但即使有这些选项,仍然需要进行许多检查才能从树中提取信息.例如,/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} };
}
Run Code Online (Sandbox Code Playgroud)
在另一个解析器中,可以使用以下内容:
my @eles = $doc->findnodes('/root/eles/ele');
Run Code Online (Sandbox Code Playgroud)
它对于生成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 :: Simple最简单的唯一格式是没有元素是可选的格式.我有过无数XML格式的经验,而且我从未遇到过这样的格式.
仅仅这种脆弱性和复杂性就足以保证远离XML :: Simple,但还有其他原因.
我使用XML :: LibXML.它是一个非常快速,功能齐全的解析器.如果我需要处理不适合内存的文档,我会使用XML :: LibXML :: Reader(及其copyCurrentNode(1))或XML :: Twig(使用twig_roots).
| 归档时间: |
|
| 查看次数: |
10302 次 |
| 最近记录: |