xml perl xml-simple

¿Por qué se desalienta XML:: Simple?



perl xml-simple (3)

No estoy de acuerdo con los documentos

Disentiré y diré que XML::Simple es solo eso ... simple. Y, siempre ha sido fácil y agradable para mí usar. Pruébelo con la entrada que está recibiendo. Mientras la entrada no cambie, eres bueno. Las mismas personas que se quejan de usar XML::Simple quejan de usar JSON::Syck para serializar Moose. Los documentos están equivocados porque tienen en cuenta la corrección sobre la eficiencia. Si solo te importa lo siguiente, eres bueno:

  • no tirar datos
  • construyendo a un formato suministrado y no a un esquema abstracto

Si está haciendo un analizador abstracto que no está definido por la aplicación sino por las especificaciones, usaría algo más. Trabajé en una empresa una vez y tuvimos que aceptar 300 esquemas diferentes de XML, ninguno de los cuales tenía una especificación. XML::Simple hizo el trabajo fácilmente. Las otras opciones nos habrían requerido contratar a alguien para hacer el trabajo. Todos piensan que XML es algo que se envía en un formato rígido que abarca todo lo especificado, de modo que si escribe un analizador está bien. Si ese es el caso, no use XML::Simple . XML, antes de JSON, era solo un formato "volcar esto y caminar" de un idioma a otro. La gente realmente usaba cosas como XML::Dumper . En realidad, nadie sabía lo que salía. Lidiando con ese escenario XML::Simple es genial! Las personas sensatas aún se vuelcan a JSON sin especificaciones para lograr lo mismo. Así es como funciona el mundo.

¿Quiere leer los datos y no preocuparse por el formato? ¿Quiere atravesar estructuras Perl y no posibilidades XML? Ir XML::Simple .

Por extensión...

Del mismo modo, para la mayoría de las aplicaciones JSON::Syck es suficiente para volcar esto y caminar. Aunque si está enviando a mucha gente, le sugiero que no sea una boquilla de ducha y haga una especificación a la que exporta. Pero, sabes qué ... En algún momento recibirás una llamada de alguien con quien no quieras hablar y que quiera sus datos que normalmente no exportas. Y, lo canalizará a través del vudú de JSON::Syck y dejará que se preocupen por eso. Si quieren XML? Cárguelos $ 500 más y enciéndalos XML::Dumper .

Para llevar

Puede ser menos que perfecto, pero XML::Simple es muy eficiente. Cada hora ahorrada en esta arena puede potencialmente gastar en una arena más útil. Esa es una consideración del mundo real.

Las otras respuestas

Mira XPath tiene algunas ventajas. Cada respuesta aquí se reduce a preferir XPath sobre Perl. Esta bien. Si prefiere utilizar un lenguaje específico de dominio XML estandarizado para acceder a su XML, ¡no lo dude!

Perl no proporciona un mecanismo fácil para acceder a estructuras opcionales profundamente anidadas.

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

Obtener el valor de foo aquí en estos dos contextos puede ser complicado. XML::Simple sabe y es por eso que puede forzar el primero. Sin embargo, incluso con ForceArray , si el elemento no está allí, arrojará un error.

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

ahora, si la bar es opcional, queda accediendo a ella $xml->{bar}[0]{foo} y @{$xml->{bar}}[0] arrojará un error. De todos modos, eso es solo perl. Esto tiene 0 que ver con XML::Simple imho. Y, admití que XML::Simple no es bueno para construir según especificaciones. Muéstrame datos y puedo acceder a ellos con XML :: Simple.

De la documentación de XML::Simple :

Se desaconseja el uso de este módulo en código nuevo. Hay otros módulos disponibles que proporcionan interfaces más directas y consistentes. En particular, XML :: LibXML es muy recomendable.

Los principales problemas con este módulo son la gran cantidad de opciones y las formas arbitrarias en que interactúan estas opciones, a menudo con resultados inesperados.

¿Alguien puede aclararme cuáles son las razones clave para esto?


XML :: Simple es el analizador XML más complejo disponible

El principal problema con XML :: Simple es que la estructura resultante es extremadamente difícil de navegar correctamente. $ele->{ele_name} puede devolver cualquiera de los siguientes (incluso para elementos que siguen la misma especificación):

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

Esto significa que debe realizar todo tipo de comprobaciones para ver lo que realmente obtuvo. Pero la gran complejidad de esto alienta a los desarrolladores a hacer suposiciones muy malas. Esto lleva a todo tipo de problemas que pasan a la producción, lo que hace que el código en vivo falle cuando se encuentran casos de esquina.

Las opciones para hacer que un árbol más regular se quede corto

Puede usar las siguientes opciones para crear un árbol más regular:

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

Pero incluso con estas opciones, aún se necesitan muchas comprobaciones para extraer información de un árbol. Por ejemplo, obtener los nodos /root/eles/ele de un documento es una operación común que debería ser trivial de realizar, pero se requiere lo siguiente cuando se utiliza 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} }; }

En otro analizador, uno usaría lo siguiente:

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

XML :: Simple impone numerosas limitaciones y carece de características comunes

  • Es completamente inútil para producir XML. Incluso con ForceArray => 1, ForceContent => 1, KeyAttr => [], KeepRoot => 1 , hay demasiados detalles que no se pueden controlar.

  • No conserva el orden relativo de los niños con nombres diferentes.

  • Tiene soporte limitado (con backend XML :: SAX) o no (con backend XML :: Parser) para espacios de nombres y prefijos de espacios de nombres.

  • No puede manejar elementos con texto y elementos como elementos secundarios (lo que significa que no puede manejar XHTML, entre otros).

  • Algunos backends (por ejemplo, XML :: Parser) no pueden manejar codificaciones no basadas en ASCII (por ejemplo, UTF-16le).

  • Un elemento no puede tener un elemento hijo y un atributo con el mismo nombre.

  • No puede crear documentos XML con comentarios.

Ignorando los principales problemas mencionados anteriormente, XML :: Simple aún podría utilizarse con estas limitaciones. Pero, ¿por qué tomarse la molestia de verificar si XML :: Simple puede manejar el formato de su documento y arriesgarse a tener que cambiar a otro analizador más tarde? Simplemente podría usar un mejor analizador para todos sus documentos desde el principio.

Algunos otros analizadores no solo no están sujetos a estas limitaciones, sino que también ofrecen muchas otras funciones útiles. Las siguientes son algunas características que podrían tener que XML :: Simple no:

  • Velocidad. XML :: Simple es extremadamente lento, especialmente si usa un backend que no sea XML :: Parser. Estoy hablando de órdenes de magnitud más lento que otros analizadores.

  • Selectores XPath o similar.

  • Soporte para documentos extremadamente grandes.

  • Soporte para una bonita impresión.

¿XML :: Simple es útil alguna vez?

El único formato para el que XML :: Simple es más simple es aquel en el que ningún elemento es opcional. He tenido experiencia con innumerables formatos XML, y nunca me he encontrado con ese formato.

Esta fragilidad y complejidad por sí solas son razones suficientes para justificar mantenerse alejado de XML :: Simple, pero hay otras.

Alternativas

Yo uso XML :: LibXML. Es un analizador extremadamente rápido y completo. Si alguna vez necesito manejar documentos que no caben en la memoria, usaría XML :: LibXML :: Reader (y su copyCurrentNode(1) ) o XML :: Twig (usando twig_roots ).


El verdadero problema es que lo que XML::Simple intenta principalmente hacer es tomar XML y representarlo como una estructura de datos perl.

Como sin duda perldata por perldata las dos estructuras de datos clave que tiene disponibles son el hash y la array .

  • Las matrices son escalares ordenados.
  • los hashes son pares desordenados de clave-valor.

Y XML tampoco lo hace realmente. Tiene elementos que son:

  • no tiene un nombre exclusivo (lo que significa que los hashes no "encajan").
  • .... pero están ''ordenados'' dentro del archivo.
  • puede tener atributos (que podría insertar en un hash)
  • puede tener contenido (pero puede que no, pero podría ser una etiqueta unaria)
  • puede tener hijos (de cualquier profundidad)

Y estas cosas no se asignan directamente a las estructuras de datos de Perl disponibles, en un nivel simplista, podría encajar un hash anidado de hashes, pero no puede hacer frente a elementos con nombres duplicados. Tampoco puede diferenciar fácilmente entre atributos y nodos secundarios.

Por lo tanto, XML::Simple intenta adivinar en función del contenido XML, y toma ''pistas'' de las diversas configuraciones de opciones, y luego, cuando intenta generar el contenido, (aplica) aplica el mismo proceso a la inversa.

Como resultado, para cualquier cosa que no sea el XML más simple , se vuelve difícil de manejar en el mejor de los casos, o pierde datos en el peor.

Considerar:

<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>

Esto, cuando se analiza a través de XML::Simple le ofrece:

$VAR1 = { ''parent'' => { ''child'' => { ''att'' => ''some_att'', ''content'' => ''content'' } }, ''another_node'' => { ''another_child'' => [ { ''some_att'' => ''a value'' }, { ''different_att'' => ''different_value'', ''content'' => ''more content'' } ] } };

Nota: ahora tiene debajo de parent , solo hashes anónimos, pero debajo de another_node tiene una matriz de hashes anónimos.

Entonces, para acceder al contenido del child :

my $child = $xml -> {parent} -> {child} -> {content};

Observe cómo tiene un nodo ''hijo'', con un nodo ''contenido'' debajo, lo cual no es porque sea ... contenido.

Pero para acceder al contenido debajo del primer elemento another_child :

my $another_child = $xml -> {another_node} -> {another_child} -> [0] -> {content};

Tenga en cuenta cómo: debido a que tiene varios elementos <another_node> , el XML se ha analizado en una matriz, donde no fue con uno solo. (Si tenía un elemento llamado content debajo de él, entonces todavía tiene algo más). Puede cambiar esto usando ForceArray pero luego termina con un hash de matrices de hash de matrices de hash de matrices, aunque al menos es consistente en el manejo de elementos secundarios. Editar: Nota, después de la discusión: este es un mal valor predeterminado, en lugar de una falla con XML :: Simple.

Debes configurar:

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

Si aplica esto al XML como se indica arriba, obtendrá en su lugar:

$VAR1 = { ''another_node'' => [ { ''another_child'' => [ { ''some_att'' => ''a value'' }, { ''different_att'' => ''different_value'', ''content'' => ''more content'' } ] } ], ''parent'' => [ { ''child'' => [ { ''att'' => ''some_att'', ''content'' => ''content'' } ] } ] };

Esto le dará coherencia, ya que ya no tendrá elementos de un solo nodo manejados de manera diferente a varios nodos.

Pero aún así:

  • Tener un árbol profundo de 5 referencias para obtener un valor.

P.ej:

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

Todavía tiene content y elementos hash child tratados como si fueran atributos, y debido a que los hash no están ordenados, simplemente no puede reconstruir la entrada. Básicamente, debes analizarlo y luego Dumper por Dumper para descubrir dónde debes buscar.

Pero con una consulta xpath , llega a ese nodo con:

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

Lo que no obtienes en XML::Simple que haces en XML::Twig (y supongo que XML::LibXML pero lo sé menos):

  • Soporte de xpath . xpath es una forma XML de expresar una ruta a un nodo. Entonces puede ''encontrar'' un nodo en lo anterior con get_xpath(''//child'') . Incluso puede usar atributos en el xpath , como get_xpath(''//another_child[@different_att]'') que seleccionará exactamente cuál desea. (También puedes iterar en los partidos).
  • cut y paste para mover elementos
  • parsefile_inplace para permitirle modificar XML con una edición en el lugar.
  • opciones de pretty_print , para formatear XML .
  • twig_handlers y purge , que le permite procesar XML realmente grande sin tener que cargarlo todo en la memoria.
  • simplify si realmente debe hacerlo compatible con XML::Simple .
  • el código generalmente es mucho más simple que tratar de seguir cadenas de referencias a hashes y matrices, que nunca se puede hacer de manera consistente debido a las diferencias fundamentales en la estructura.

También está ampliamente disponible: fácil de descargar desde CPAN y distribuido como un paquete instalable en muchos sistemas operativos. (Lamentablemente, no es una instalación predeterminada. Todavía)

Ver: XML :: Referencia rápida de Twig

Por el bien de la comparación:

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'');