XML::Simple
のドキュメントから:
新しいコードでこのモジュールを使用することはお勧めしません。より簡単で一貫したインターフェースを提供する他のモジュールが利用可能です。特に、XML :: LibXMLを強くお勧めします。
このモジュールの主な問題は、多数のオプションと、これらのオプションが相互に作用するarbitrary意的な方法です。多くの場合、予期しない結果が生じます。
誰かが私のためにこれの主な理由を明確にすることはできますか?
本当の問題は、XML::Simple
が主にしようとすることはXMLを取得し、それをPerlデータ構造として表すことです。
間違いなく perldata
に気づくでしょう。利用できる2つの主要なデータ構造はhash
とarray
です。
また、XMLも実際には機能しません。次の要素があります。
そして、これらは利用可能なPerlデータ構造に直接マッピングされません-単純化されたレベルでは、ハッシュのネストされたハッシュが適合するかもしれませんが、重複した名前を持つ要素には対処できません。また、属性と子ノードを簡単に区別することもできません。
したがって、XML::Simple
は、XMLコンテンツに基づいて推測を試み、さまざまなオプション設定から「ヒント」を取得します。その後、コンテンツを試してoutput、同じプロセスを逆に適用(試行)します。
その結果、ほとんどのsimpleXML以外の場合、せいぜい扱いにくくなるか、最悪の場合データを失います。
考慮してください:
<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は1つの配列ではなく、配列に解析されています。 (その下に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'
}
]
}
]
};
これにより、マルチノードとは異なる単一ノード要素の処理がなくなるため、一貫性が得られます。
しかし、あなたはまだ:
例えば。:
print $xml -> {parent} -> [0] -> {child} -> [0] -> {content};
content
およびchild
ハッシュ要素は属性であるかのように扱われ、ハッシュは順序付けられていないため、単に入力を再構築することはできません。したがって、基本的には、それを解析し、Dumper
を介して実行する必要があります。
しかし、xpath
クエリでは、次のようにしてそのノードに到達します。
findnodes("/xml/parent/child");
あなたが XML::Simple
で行うXML::Twig
で得られないもの(そしてXML::LibXML
と仮定しますが、私はそれをあまりよく知りません):
xpath
サポート。 xpath
は、ノードへのパスを表現するXMLの方法です。したがって、get_xpath('//child')
を使用して上記のノードを「見つける」ことができます。 xpath
で属性を使用することもできます-get_xpath('//another_child[@different_att]')
のように、必要な属性を正確に選択します。 (マッチについても繰り返すことができます)。cut
およびpaste
は要素を移動しますparsefile_inplace
を使用して、インプレース編集でXML
を変更できます。XML
をフォーマットするpretty_print
オプション。twig_handlers
およびpurge
-これにより、メモリにすべてをロードすることなく、非常に大きなXMLを処理できます。XML::Simple
との後方互換性が本当に必要な場合は、simplify
。また、CPAN
から簡単にダウンロードでき、多くのオペレーティングシステムにインストール可能なパッケージとして配布されています。 (残念ながら、デフォルトのインストールではありません。しかし)
比較のために:
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');
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の作成にはまったく役に立ちません。 _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 :: Parser以外のバックエンドを使用する場合は特に、XML :: Simpleは非常に遅くなります。私は他のパーサーよりも桁違いに遅い話をしています。
XPathセレクターなど。
非常に大きなドキュメントのサポート。
プリティ印刷のサポート。
XML :: Simpleが最も単純な形式は、オプションの要素がない形式のみです。私は無数のXMLフォーマットの経験があり、そのようなフォーマットに出会ったことはありません。
この脆弱性と複雑さだけでも、XML :: Simpleから離れることを保証するのに十分な理由ですが、他にもあります。
XML :: LibXMLを使用します。非常に高速でフル機能のパーサーです。メモリに収まらないドキュメントを処理する必要がある場合、XML :: LibXML :: Reader(およびそのcopyCurrentNode(1)
)またはXML :: Twig(_twig_roots
_を使用)を使用します。
私は異議を唱え、XML::Simple
はまさにそれだと言います。そして、私にとってはいつも使いやすくて楽しいものでした。受け取った入力でテストします。入力が変更されない限り、あなたは大丈夫です。 XML::Simple
の使用について文句を言う同じ人々は、JSON::Syck
を使用してMooseをシリアル化することについて文句を言います。ドキュメントは、効率よりも正確さを考慮しているため、間違っています。次のことだけを気にするなら、あなたは大丈夫です:
アプリケーションではなく仕様で定義されている抽象パーサーを作成している場合は、別のものを使用します。ある会社で働いたことがありますが、仕様のないXMLスキーマを300種類受け入れなければなりませんでした。 XML::Simple
は簡単に仕事をしました。他のオプションでは、仕事を成し遂げるために実際に誰かを雇う必要がありました。 XMLは、パーサーを1つ記述するだけでよいように、すべてが仕様に準拠した厳密な形式で送信されるものだと考えています。その場合は、XML::Simple
を使用しないでください。 JSONは、JSONの前に、ある言語から別の言語への「これをダンプして歩く」形式でした。人々は実際にXML::Dumper
のようなものを使用しました。何が出力されたのか実際には誰も知りませんでした。そのシナリオに対処するXML::Simple
は素晴らしいです!同じことを達成するために、健全な人々はまだ仕様なしでJSONにダンプします。それはまさに世界の仕組みです。
データを読み込みたいのですが、フォーマットについて心配しませんか? XMLの可能性ではなく、Perl構造をトラバースしたいですか? XML::Simple
に移動します。
同様に、mostアプリケーションJSON::Syck
で十分ですこれをダンプして歩いてください。多くの人に送信する場合、私は非常に潅水ノズルではなく、エクスポート先の仕様を作成することを提案します。しかし、あなたは何を知っていますか。いつかは、通常はエクスポートしないデータを望んでいる人と話をしたくない人から電話を受けるでしょう。そして、あなたはJSON::Syck
のブードゥーを通してそれをパイプして、彼らにそれを心配させます。 XMLが必要ですか?彼らにさらに500ドルを請求し、あなたがたのオレXML::Dumper
を起動します。
完全ではないかもしれませんが、XML::Simple
は非常に効率的です。このアリーナで節約された1時間ごとに、より有用なアリーナで潜在的に過ごすことができます。それは現実世界の考慮事項です。
XPathにはいくつかの利点があります。ここでのすべての答えは、PerlよりもXPathを好むことに要約されます。それはいいです。標準化されたXMLドメイン固有の言語を使用してXMLにアクセスする場合は、ぜひお試しください。
Perlは、深くネストされたオプション構造にアクセスする簡単なメカニズムを提供していません。
var $xml = [ { foo => 1 } ]; ## Always w/ ForceArray.
var $xml = { foo => 1 };
これら2つのコンテキストで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でアクセスできます。