IT TIP

XML :: Simple이 권장되지 않는 이유는 무엇입니까?

itqueen 2021. 1. 7. 20:16
반응형

XML :: Simple이 권장되지 않는 이유는 무엇입니까?


의 문서에서 XML::Simple:

새 코드에서이 모듈을 사용하는 것은 권장되지 않습니다. 보다 간단하고 일관된 인터페이스를 제공하는 다른 모듈을 사용할 수 있습니다. 특히 XML :: LibXML을 적극 권장합니다.

이 모듈의 주요 문제점은 많은 옵션과 이러한 옵션이 상호 작용하는 임의의 방법입니다. 종종 예기치 않은 결과가 발생합니다.

누군가가 이것의 주요 이유를 설명해 줄 수 있습니까?


진짜 문제는 XML::Simple주로 XML을 가져 와서 펄 데이터 구조로 표현하는 것입니다.

당신은 의심의 여지가에서 인식하지 겠지만 perldata당신이 사용할 수있는 두 가지 핵심 데이터 구조는 IS hash와를 array.

  • 배열은 정렬 된 스칼라입니다.
  • 해시는 정렬되지 않은 키-값 쌍입니다.

그리고 XML도 그렇게하지 않습니다. 다음과 같은 요소가 있습니다.

  • 고유하지 않은 이름 (해시가 "적합"하지 않음을 의미).
  • .... 그러나 파일 내에서 '정렬'됩니다.
  • 속성이있을 수 있습니다 (해시에 삽입 할 수 있음)
  • 콘텐츠가있을 수 있음 (하지만 그렇지 않을 수 있지만 단항 태그 일 수 있음)
  • 자녀가있을 수 있음 (모든 깊이)

그리고 이러한 것들은 사용 가능한 perl 데이터 구조에 직접 매핑되지 않습니다. 단순한 수준에서 해시의 중첩 된 해시가 적합 할 수 있지만 중복 된 이름을 가진 요소에는 대처할 수 없습니다. 또한 속성과 자식 노드를 쉽게 구분할 수 없습니다.

따라서 XML::SimpleXML 콘텐츠를 기반으로 추측을 시도하고 다양한 옵션 설정에서 '힌트'를 가져온 다음 콘텐츠를 출력 하려고 시도하면 동일한 프로세스를 반대로 적용 (시도)합니다.

결과적으로 가장 단순한 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};

그 아래에 'content'노드가있는 'child'노드가있는 방법에 유의하십시오. 이는 콘텐츠 때문이 아닙니다.

그러나 첫 번째 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'). 당신도에서 속성을 사용할 수 있습니다 xpath같은 - get_xpath('//another_child[@different_att]')당신이 원하는 정확히 어느 하나를 선택할 것이다. (당신도 경기를 반복 할 수 있습니다).
  • cutpaste주변 요소를 이동
  • parsefile_inplaceXML내부 편집 으로 수정할 수 있습니다 .
  • 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};

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은 사용 가능한 가장 복잡한 XML 파서입니다.

The main problem with XML::Simple is that the resulting structure is extremely hard to navigate correctly. $ele->{ele_name} can return any of the following (even for elements that follow the same spec):

[ { 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'

This means that you have to perform all kinds of checks to see what you actually got. But the sheer complexity of this encourages developers to make very bad assumptions instead. This leads to all kinds of problems slipping into production, causing live code to fail when corner cases are encountered.

The options for making a more regular tree fall short

You can use the following options to create a more regular tree:

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

But even with these options, many checks are still needed to extract information from a tree. For example, getting the /root/eles/ele nodes from a document is a common operation that should be trivial to perform, but the following is required when using 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} };
}

In another parser, one would use the following:

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

XML::Simple imposes numerous limitations, and it lacks common features

  • It's completely useless for producing XML. Even with ForceArray => 1, ForceContent => 1, KeyAttr => [], KeepRoot => 1, there are far too many details that can't be controlled.

  • It doesn't preserve the relative order of children with different names.

  • It has limited (with XML::SAX backend) or no (with XML::Parser backend) support for namespaces and namespace prefixes.

  • It can't handle elements with both text and elements as children (which means it can't handle XHTML, among others).

  • Some backends (e.g. XML::Parser) are unable to handle encodings not based on ASCII (e.g. UTF-16le).

  • An element can't have a child element and an attribute with the same name.

  • It can't create XML documents with comments.

Ignoring the major issues previously mentioned, XML::Simple could still be usable with these limitations. But why go to the trouble of checking if XML::Simple can handle your document format and risk having to switch to another parser later? You could simply use a better parser for all your documents from the start.

Not only do some other parsers not subject you to these limitations, they provide loads of other useful features in addition. The following are a few features they might have that XML::Simple doesn't:

  • Speed. XML::Simple is extremely slow, especially if you use a backend other than XML::Parser. I'm talking orders of magnitude slower than other parsers.

  • XPath selectors or similar.

  • Support for extremely large documents.

  • Support for pretty printing.

Is XML::Simple ever useful?

The only format for which XML::Simple is simplest is one where no element is optional. I've had experience with countless XML formats, and I've never encountered such a format.

This fragility and complexity alone are reasons enough to warrant staying away from XML::Simple, but there are others.

Alternatives

I use XML::LibXML. It's an extremely fast, full-featured parser. If I ever needed to handle documents that didn't fit into memory, I'd use XML::LibXML::Reader (and its copyCurrentNode(1)) or XML::Twig (using twig_roots).


I disagree with the docs

I'll dissent and say that XML::Simple is just that.. simple. And, it's always been easy and enjoyable for me to use. Test it with the input you're receiving. So long as the input does not change, you're good. The same people that complain about using XML::Simple complain about using JSON::Syck to serialize Moose. The docs are wrong because they take into account correctness over efficiency. If you only care about the following, you're good:

  • not throwing away data
  • building to a format supplied and not an abstract schema

If you're making an abstract parser that isn't defined by application but by spec, I'd use something else. I worked at a company one time and we had to accept 300 different schemas of XML none of which had a spec. XML::Simple did the job easily. The other options would have required us to actually hire someone to get the job done. Everyone thinks XML is something that is sent in a rigid all encompassing spec'ed format such that if you write one parser you're good. If that's the case don't use XML::Simple. XML, before JSON, was just a "dump this and walk" format from one language to another. People actually used things like XML::Dumper. No one actually knew what was outputted. Dealing with that scenario XML::Simple is greattt! Sane people still dump to JSON without spec to accomplish the same thing. It's just how the world works.

Want to read the data in, and not worry about the format? Want to traverse Perl structures and not XML possibilities? Go XML::Simple.

By extension...

Likewise, for most applications JSON::Syck is sufficient to dump this and walk. Though if you're sending to lots of people, I'd highly suggest not being a douche nozzle and making a spec which you export to. But, you know what.. Sometime you're going to get a call from someone you don't want to talk to who wants his data that you don't normally export. And, you're going to pipe it through JSON::Syck's voodoo and let them worry about it. If they want XML? Charge them $500 more and fire up ye' ole XML::Dumper.

Take away

It may be less than perfect, but XML::Simple is damn efficient. Every hour saved in this arena you can potentially spend in a more useful arena. That's a real world consideration.

The other answers

Look XPath has some upsides. Every answer here boils down to preferring XPath over Perl. That's fine. If you would rather use an a standardized XML domain specific language to access your XML, have at it!

Perl doesn't provide for an easy mechanism to access deeply nested optional structures.

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

var $xml = { foo => 1 };

Getting the value of foo here in these two contexts can be tricky. XML::Simple knows this and that's why you can force the former.. However, that even with ForceArray, if the element isn't there you'll throw an error..

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

now, if bar is optional, You're left accessing it $xml->{bar}[0]{foo} and @{$xml->{bar}}[0] will throw an error. Anyway, that's just perl. This has 0 to do with XML::Simple imho. And, I admitted that XML::Simple is not good for building to spec. Show me data, and I can access it with XML::Simple.

ReferenceURL : https://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged

반응형