¿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 conget_xpath(''//child'')
. Incluso puede usar atributos en elxpath
, comoget_xpath(''//another_child[@different_att]'')
que seleccionará exactamente cuál desea. (También puedes iterar en los partidos). -
cut
ypaste
para mover elementos -
parsefile_inplace
para permitirle modificarXML
con una edición en el lugar. -
opciones de
pretty_print
, para formatearXML
. -
twig_handlers
ypurge
, que le permite procesar XML realmente grande sin tener que cargarlo todo en la memoria. -
simplify
si realmente debe hacerlo compatible conXML::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'');