• Publicidad

Parseo de XML muy raro

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Notapor Sombrerero_Loco » 2008-12-23 04:57 @248

¿Y qué módulo me recomiendas?

Te comento, esto genera una estructura de jerarquías que otro programa usa para leer e interpretar, es decir, chupa esta información y la representa gráficamente.

Bien, el problema es que no trata esta jerarquía de la manera que un xml la representaría.

XML abre con un nodo raíz, para la primera rama del árbol, abre un nodo, dentro de este otro, dentro de este otro, etc. etc... así hasta llegar al ultimo nodo (como el desplegable del árbol de directorios de un Windows o Linux).

Bien, este programa lo hace de manera lineal, no en modo de arboles.

Es decir, si quiero pintar una rama desde el tronco hasta la punta, primero abro con service, digo los elementos que tiene por debajo, cierro service. Abro service, selecciono el primer elemento de los que antes dije y represento qué elementos tiene por debajo, cierro service. Vuelvo abrir service, del anterior elemento y declaro que tiene por debajo, si no tiene nada, no declaro nada, cierro service. Vuelvo abrir service y me voy al "nivel" anterior y voy con el siguiente de ese nivel, etc. así hasta terminar todas las ramas.

Como veis es un sistema del diablo que menuda tela quien lo "parió" porque lo normal sería que usara el estándar de xml que es tremendamente más sencillo para eso y viene dado de una forma "nativa" al formato del fichero, pero no.

Cuál es el principal problema de esto: que elementos que pertenecen al mismo nivel de jerarquía, no están dentro del mismo nivel de tags, con lo que tengo que construir yo esa jerarquía a nivel de hashes para luego quizás exportarlo como dios manda en su formato xml.

La opción que más se me está acercando es no usar el XML::simple ya que no me sirve, para acceder a la información del xml si, pero para parsearlo en su manera correcta no, con lo que debería de ir escaneando con bucles cada rama, indicando que busque valores de un array que sería el nivel anterior, dentro del xml, con expresiones regulares.

¿Qué os parece? ¿Sudaré tinta china?
Sombrerero_Loco
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2008-11-11 11:20 @514

Publicidad

Notapor explorer » 2008-12-23 11:47 @533

Si el resulto de todo es un xml en forma jerárquica, entonces es natural que debas construir ese árbol.

En este problema, lo curioso es la forma de obtener las hojas y ramas de ese árbol: que está por descripción de cada nodo.

Yo creo que no sería muy complicado leer los nodos e ir agregando las ramas y nodos como nuevos nodos, y así crear una estructura jerárquica.

Es un problema muy interesante para la asignatura de Estructuras de datos...

Ahora solo nos queda por saber qué aspecto quieres para el xml de salida.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Sombrerero_Loco » 2008-12-23 11:58 @540

Hola explorer.

Lo he conseguido responder, he estado foreando, consultando, leyendo...llevo 2 días de terror pero aquí está:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
use Data::Dumper;
$fichero_xml = "c:\\fichero_xml.xml";
$contador = 0000;
$ident = "ID" . $contador;
print "$ident\n";
$name = ();
$label = ();
$serviceref = ();
my %index;

open (FICHERO, "<$fichero_xml");
while (<FICHERO>) {
    if (/<Service>/ .. /<\/Service>/) {
        if (/<Name>(.+?)<\/Name>/){
            $name = $1;
            $index{"nombre"} = $name;
        }
        elsif (/<Label>(.+?)<\/Label>/) {
            $label = $1;
            #print "LABEL:$label\n";
            $index{$name}{"label"} = $label;
        }
        elsif (/<ServiceRef>(.+?)<\/ServiceRef>/) {
            $serviceref = $1;
            $contador++;
            #print "HIJOS:$serviceref ID$contador\n";
            $index{$name}{"hijos"} = $serviceref;
            warn Dumper %index;
        }
    }
}
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Ahora me asalta otra duda, ya he conseguido tenerlo todo (incluso hay gente que al verlo se ha quedado bastante aturdida de como con if (/<Service>/ .. /<\/Service>/) consigo sacar todo lo que esté entre esos dos tags), lo que me falla es que quiero asignar la variable $name a la primera clave del hash %index.

Había pensado algo al estilo de esto dentro de aquí:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if (/<Name>(.+?)<\/Name>/){
    $name = $1;
    $index{"nombre"} = $index{$name};
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


¿Alguna idea sobre cómo hacer eso?
Sombrerero_Loco
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2008-11-11 11:20 @514

Notapor explorer » 2008-12-23 12:23 @558

Días de terror, nada (has aprendido mucho), salvo que te hayan amenazado con cortarte las manos.

La forma de leer los nodos está bien, pero resulta que es otra forma distinta de tener la información que, ya antes, XML::Simple nos ha entregado. Has creado un parser sencillo porque la estructura es sencilla.

Lo interesante es saber qué aspecto debe tener lo que quieres conseguir.

Y sobre la pregunta: no tiene sentido hablar de "primera clave" de un hash: las claves no se guardan en los hash sin ningún orden especial.

La única forma que tienes de saber ese orden sería guardándolo en varias intermedias, como muestras, o en un array.

Ahora bien... si te refieres a la primera clave que te encuentras al leer el fichero, entonces sí deberías usar esas líneas (si estás seguro que el nodo Name no volverá a salir).

Creo que hay un error a la hora de guardar los nodos hijo, dentro del if() del ServiceRef. Yo creo que debería ser:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
            push @{$index{$name}{"hijos"}}, $serviceref;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Y entonces, sale:
Código: Seleccionar todo
$VAR1 = {
          '69970093-C777-494C-BE61-E9CDBFF99582' => {
                                                      'hijos' => [
                                                                   'opc_adm (discovered)',
                                                                   'usuario1 (discovered)',
                                                                   'usuario2(discovered)',
                                                                   'usuario3 (discovered)',
                                                                   'usuario4 (discovered)',
                                                                   'usuario5 (discovered)'
                                                                 ],
                                                      'label' => 'Virtual top node (don\'t remove)'
                                                    },
          'opc_adm (discovered)' => {
                                      'hijos' => [
                                                   'SVCDISC:System',
                                                   'SVCDISC:Applications',
                                                   'HP OpenView Operations',
                                                   'SGC'
                                                 ],
                                      'label' => 'opc_adm'
                                    },
          'nombre' => 'opc_adm (discovered)'
        };
pero yo creo que no es lo que quieres... la clave 'nombre' ha sido sobreescrita varias veces a lo largo del proceso: cada vez que aparecía un nuevo Service.

Lo dicho, necesitamos saber el aspecto de lo que quieres conseguir. O dicho de otra manera, qué es lo que debe contener cada nodo y cómo referenciar a los demás nodos hijos (¿hash de array? ¿array de array de hash?)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Jenda » 2008-12-23 12:57 @581

Sí, todo sería más fácil si supiéramos la estructura que quieres obtener. Quizás es culpa de mi español pero no comprendí tu explicación anterior. Nos muestras un ejemplo de la estructura de datos que necesitas obtener del ejemplo de XML y veremos si lo podemos hacer.

Generalmente, no creo que sea sabio parsear XML con expresiones regulares. Si el archivo que tienes no es un XML correcto, creo que sería mejor, arreglarlo y después usar un módulo.

Si el único problema es que no hay un único raíz, lo más fácil es pedir al módulo a parsear

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
qq{<!DOCTYPE doc [<!ENTITY real_doc SYSTEM "$el_nombre_del_fichero">]><doc>&real_doc;</doc>}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
-------------------------------------------------------
- Estoy aquí para practicar español. Si te ayudó mi respuesta ayudame con un mensaje privado sobre mis faltas por favor. Seguramente habrá muchas :-)
Jenda
Perlero nuevo
Perlero nuevo
 
Mensajes: 132
Registrado: 2007-10-29 06:31 @313
Ubicación: Praga, Republica Checa

Notapor Sombrerero_Loco » 2008-12-24 05:39 @277

¡Hola!

Muchísimas gracias por la ayuda que me estáis prestando, voy a tener que invitaros a algo un día de estos :)

Bien, al turrón: esto es lo que quiero guardar según vaya leyendo el fichero "xml":

Código: Seleccionar todo
%index   {$ID.$contador}   {"label"} = $name
            {"nivel"} = nivel en el que esta
            {"Hijos"}   {$variable que me sume uno en cada iteracion} = "ID.$contador"
            {"Hijos"}   {$variable + 1} = "ID.$contador"
            {"Hijos"}   {$variable + 2} = "ID.$contador"
            {"Hijos"}   {$variable + nveces} = "ID.$contador"
            "hijos son los serviceref que detecta por entre <service> y </service> y que empiezan por <ServiceRef> ...</..."
            
%index   {$ID.$contador}   {"label"} = $name
                  {"nivel"} = Nivel del padre mas 1


Como veis esto es la estructura de los hashes que he ideado, en cada línea porción de código entre <service> y </service> se declara primero el padre, y luego en cada ServiceRef los nombres de los hijos. Para simplificarlo, he hecho que en cada porción obtenga toda la info del padre y a su vez en cada servicef, obtenga el nombre del hijo y el nivel que tiene asignado (que es el nivel del padre + 1).
Esto me dará un hash donde tendré mi identificador interno (ID.$contador) y éste tiene anidados todos los datos de todos los hijos, con sus niveles y los label (que es el nombre original del servicio).

Esto luego lo escupiré en un XML como dios manda, jerarquizado, seguramente por los niveles, o reestructurare la información para que según los padres y el nivel en el que esté, se me quede guardado así en el hash.

Aparte de esto... ¡¡¡Os deseo feliz Navidad a todos!!!
Sombrerero_Loco
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2008-11-11 11:20 @514

Notapor explorer » 2008-12-24 11:15 @510

Una idea, a ver si te sirve, al menos, de inspiración:
Supongamos que tenemos el fichero
Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
<Service>
  <Name>69970093-C777-494C-BE61-E9CDBFF99582</Name>
  <Label>Virtual top node (don't remove)</Label>
  <Description>Dont delete</Description>
  <Source>
    <Composition/>
    <ServiceRef>opc_adm (discovered)</ServiceRef>
  </Source>
  <Source>
    <Composition/>
    <ServiceRef>usuario1 (discovered)</ServiceRef>
  </Source>
  <Source>
    <Composition/>
    <ServiceRef>usuario2(discovered)</ServiceRef>
  </Source>
  <Source>
    <Composition/>
    <ServiceRef>usuario3 (discovered)</ServiceRef>
  </Source>
  <Source>
    <Composition/>
    <ServiceRef>usuario4 (discovered)</ServiceRef>
  </Source>
  <Source>
    <Composition/>
    <ServiceRef>usuario5 (discovered)</ServiceRef>
  </Source>
</Service>
<Service>
  <Name>opc_adm (discovered)</Name>
  <Label>opc_adm</Label>
  <MsgWeight>1.0</MsgWeight>
  <MsgPropRuleRef>Unchanged</MsgPropRuleRef>
  <Icon>services.32.gif</Icon>
  <CalcRuleRef>Most critical</CalcRuleRef>
  <Source>
  <Dependency/>
  <ServiceRef>SVCDISC:System</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
  <Source>
  <Dependency/>
  <ServiceRef>SVCDISC:Applications</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
  <Source>
  <Dependency/>
  <ServiceRef>HP OpenView Operations</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
  <Source>
  <Dependency/>
  <ServiceRef>SGC</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
</Service>
<Service>
  <Name>usuario1 (discovered)</Name>
  <Label>usuario1</Label>
  <MsgWeight>1.0</MsgWeight>
  <MsgPropRuleRef>Unchanged</MsgPropRuleRef>
  <Icon>services.32.gif</Icon>
  <CalcRuleRef>Most critical</CalcRuleRef>
</Service>
<Service>
  <Name>SVCDISC:System</Name>
  <Label>SVCDISC</Label>
  <MsgWeight>1.0</MsgWeight>
  <MsgPropRuleRef>Unchanged</MsgPropRuleRef>
  <Icon>services.32.gif</Icon>
  <CalcRuleRef>Most critical</CalcRuleRef>
  <Source>
  <Dependency/>
  <ServiceRef>SVCDISC1:System</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
  <Source>
  <Dependency/>
  <ServiceRef>SVCDISC1:Applications</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
  <Source>
  <Dependency/>
  <ServiceRef>HP OpenView Operations1</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
  <Source>
  <Dependency/>
  <ServiceRef>SGC1</ServiceRef>
  <PropRuleRef>Unchanged</PropRuleRef>
  <Weight>1.0</Weight>
  </Source>
</Service>
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
que, como puedes ver, sigue tu descripción de tu fichero: los nodos están dentro de <Service>, y se relacionan entre sí por el el <ServiceRef> y el <Name>. En el ejemplo, he puesto cuatro niveles de profundidad.

Entonces, con el programa siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

use XML::Simple;
use Data::Dumper;

## Leemos el fichero
my $xml = do { local $/ = undef; open XML,"<kk.xml"; <XML> };

## Le colocamos un nodo raíz
$xml = "<root>\n$xml\n</root>\n";

## Lo parseamos
$xml = XMLin($xml, ForceArray => ['Source']);
print Dumper $xml;

## Recorremos el $xml, leyendo todos los nodos
my @nodos;
for my $nodo ( @{ $xml->{Service} } ) {

    ## Leemos el nodo
    my ($Name,$Label) = @{$nodo}{qw(Name Label)};
    my @Source;
    for my $serviceref ( @{ $nodo->{Source} } ) {
        push @Source, $serviceref->{ServiceRef};
    }

    ## Guardamos el nodo
    push @nodos, {
        label => $Name,
        hijo  => [ @Source ],
    };
}

#print Dumper \@nodos;

## Contador de nodos
my $ID = 'ID0000';

## Añadimos el nodo principal, que es el primero de la lista de @nodos
my $index = crea_nodo(0,1);

## Creamos todo el árbol
crea_arbol($index, 1);

## Recorremos el árbol de forma recursiva
## con el orden "primero en profundidad"
sub crea_arbol {
    my $padre = shift;
    my $nivel = shift;

    ## Recorremos los nodos hijos, sustituyendo su nombre
    ## por una referencia al nodo hijo (si existe)
    for my $hijo ( @{ $padre->{hijo} } ) {
        next if ref $hijo;              # No buscamos si ya es una referencia

        if (my $nodo_hijo = busca_nodo($hijo)) {
            $hijo = crea_nodo($nodo_hijo,$nivel+1);

            ## Proceso recursivo
            crea_arbol($hijo, $nivel+1);
        }
        else {
            ## Creamos un nodo con solo el nombre
            $hijo = {
                id    => ++$ID,
                label => $hijo,
                nivel => $nivel+1,
                hijo  => [],
            };
        }
    }
}

## Busca un nodo dado su nombre
## Devuelve el número de nodo encontrado o 0 si no lo encuentra
sub busca_nodo {
    my $label = shift;
    for my $i ( 0 .. $#nodos ) {
        if ($nodos[$i]->{label} eq $label) {
            return $i;
        }
    }
    return;
}

## Crea un nodo del árbol, dado el índice dentro de @nodos y el nivel de profundidad
sub crea_nodo {
    my $i     = shift;
    my $nivel = shift;

    return {
        id    => ++$ID,
        label => $nodos[$i]{label},
        nivel => $nivel,
        hijo  => [ @{$nodos[$i]{hijo}} ],
    };

print Dumper $index;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
sale
Código: Seleccionar todo
$VAR1 = {
          'label' => '69970093-C777-494C-BE61-E9CDBFF99582',
          'id' => 'ID0001',
          'hijo' => [
                      {
                        'label' => 'opc_adm (discovered)',
                        'id' => 'ID0002',
                        'hijo' => [
                                    {
                                      'label' => 'SVCDISC:System',
                                      'id' => 'ID0003',
                                      'hijo' => [
                                                  {
                                                    'label' => 'SVCDISC1:System',
                                                    'id' => 'ID0004',
                                                    'hijo' => [],
                                                    'nivel' => 4
                                                  },
                                                  {
                                                    'label' => 'SVCDISC1:Applications',
                                                    'id' => 'ID0005',
                                                    'hijo' => [],
                                                    'nivel' => 4
                                                  },
                                                  {
                                                    'label' => 'HP OpenView Operations1',
                                                    'id' => 'ID0006',
                                                    'hijo' => [],
                                                    'nivel' => 4
                                                  },
                                                  {
                                                    'label' => 'SGC1',
                                                    'id' => 'ID0007',
                                                    'hijo' => [],
                                                    'nivel' => 4
                                                  }
                                                ],
                                      'nivel' => 3
                                    },
                                    {
                                      'label' => 'SVCDISC:Applications',
                                      'id' => 'ID0008',
                                      'hijo' => [],
                                      'nivel' => 3
                                    },
                                    {
                                      'label' => 'HP OpenView Operations',
                                      'id' => 'ID0009',
                                      'hijo' => [],
                                      'nivel' => 3
                                    },
                                    {
                                      'label' => 'SGC',
                                      'id' => 'ID0010',
                                      'hijo' => [],
                                      'nivel' => 3
                                    }
                                  ],
                        'nivel' => 2
                      },
                      {
                        'label' => 'usuario1 (discovered)',
                        'id' => 'ID0011',
                        'hijo' => [],
                        'nivel' => 2
                      },
                      {
                        'label' => 'usuario2(discovered)',
                        'id' => 'ID0012',
                        'hijo' => [],
                        'nivel' => 2
                      },
                      {
                        'label' => 'usuario3 (discovered)',
                        'id' => 'ID0013',
                        'hijo' => [],
                        'nivel' => 2
                      },
                      {
                        'label' => 'usuario4 (discovered)',
                        'id' => 'ID0014',
                        'hijo' => [],
                        'nivel' => 2
                      },
                      {
                        'label' => 'usuario5 (discovered)',
                        'id' => 'ID0015',
                        'hijo' => [],
                        'nivel' => 2
                      }
                    ],
          'nivel' => 1
        };
que como ves, mantiene la jerarquía entre nodos y lleva la cuenta de los ID y el nivel de profundidad.

Si ahora quisiéramos sacarlo en formato XML, podríamos añadir una línea más:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
print XMLout($index, RootName => 'Source', NoAttr => 1, XMLDecl => 1 );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
con lo que sale:
Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
<?xml version='1.0' standalone='yes'?>
<Source>
  <id>ID0001</id>
  <hijo>
    <id>ID0002</id>
    <hijo>
      <id>ID0003</id>
      <hijo>
        <id>ID0004</id>
        <label>SVCDISC1:System</label>
        <nivel>4</nivel>
      </hijo>
      <hijo>
        <id>ID0005</id>
        <label>SVCDISC1:Applications</label>
        <nivel>4</nivel>
      </hijo>
      <hijo>
        <id>ID0006</id>
        <label>HP OpenView Operations1</label>
        <nivel>4</nivel>
      </hijo>
      <hijo>
        <id>ID0007</id>
        <label>SGC1</label>
        <nivel>4</nivel>
      </hijo>
      <label>SVCDISC:System</label>
      <nivel>3</nivel>
    </hijo>
    <hijo>
      <id>ID0008</id>
      <label>SVCDISC:Applications</label>
      <nivel>3</nivel>
    </hijo>
    <hijo>
      <id>ID0009</id>
      <label>HP OpenView Operations</label>
      <nivel>3</nivel>
    </hijo>
    <hijo>
      <id>ID0010</id>
      <label>SGC</label>
      <nivel>3</nivel>
    </hijo>
    <label>opc_adm (discovered)</label>
    <nivel>2</nivel>
  </hijo>
  <hijo>
    <id>ID0011</id>
    <label>usuario1 (discovered)</label>
    <nivel>2</nivel>
  </hijo>
  <hijo>
    <id>ID0012</id>
    <label>usuario2(discovered)</label>
    <nivel>2</nivel>
  </hijo>
  <hijo>
    <id>ID0013</id>
    <label>usuario3 (discovered)</label>
    <nivel>2</nivel>
  </hijo>
  <hijo>
    <id>ID0014</id>
    <label>usuario4 (discovered)</label>
    <nivel>2</nivel>
  </hijo>
  <hijo>
    <id>ID0015</id>
    <label>usuario5 (discovered)</label>
    <nivel>2</nivel>
  </hijo>
  <label>69970093-C777-494C-BE61-E9CDBFF99582</label>
  <nivel>1</nivel>
</Source>
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
que... bueno... no es muy bonito... pero al menos tiene una estructura jerárquica.

Seguro que Jenda (y otros) pueden hacerlo mejor :)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

¡Feliz año!

Notapor Sombrerero_Loco » 2009-01-07 04:48 @241

Bueno, después de una merecidas vacaciones vuelvo a la carga.
Edito este comentario, porque ni me había acordado que había segunda página.

Me voy a poner a echarle un vistazo, explorer, a tu código y te voy contando... en principio estaría genial que así fuera, pero estoy probando con un XML y me devuelve este error:

$VAR1 = {}; $VAR1 = { 'label' => undef, 'id' => 'ID0001', 'hijo' => [], 'nivel' => 1 };

Más bien no es un error, sino que solo lo hace la primera línea.

Aunque así sea voy a chequearlo a ver si se me ha quedado metido algún cacho turrón entre algún hash ;)

Gracias y un saludo y feliz años, reyes, navidad... etc.

Editado:

Vale, después de muchos quebraderos y pruebas he llegado a la siguiente conclusión: este script que os pego es como creo que es la forma más sencilla y clara de sacar la info:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
use Data::Dumper;
$fichero_xml = "C:\\xmlparser\\mapfre_con_root.xml";
$contador = 0000;
$ident = "ID" . $contador;
$name = ();
$label = ();
$serviceref = ();
my %index;


open (FICHERO, "<$fichero_xml");
while (<FICHERO>) {
    if (/<Service>/ .. /<\/Service>/) {

        if (/<Name>(.+?)<\/Name>/){
                $name = $1;
            $contador++;
                $index{"ID$contador"}{"nombre"} = $name;

                }
        elsif (/<Label>(.+?)<\/Label>/){
                $label = $1;
                $index{"ID$contador"}{"label"} = $label;
                                }
        elsif (/<ServiceRef>(.+?)<\/ServiceRef>/) {
           $serviceref = $1;
           $index{"ID$contador"}{"hijos"}[hijo] = $serviceref;
           ;
           }

           }
    }
close FICHERO;
warn Dumper %index
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Lo único para lo que solicito vuestra iluminación es para la línea última: $index{"ID$contador"}{"hijos"}[hijo] = $serviceref;

Aquí como veis lo que hago es que cada vez que encuentre lo que sea entre <service> y <\service>, lo mete en un array, dentro de un hash de un hash. Bien, es la primera vez que hago esto... y creo que no estoy metiendo bien el valor de $serviceref en el array [hijo] del hash %index{"ID$contador"}{"hijos"}.

Espero vuestra ayuda, a ver si encuentro yo algo de cómo hacerlo, pero no me queda muy claro...

¡Saludos!
Sombrerero_Loco
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2008-11-11 11:20 @514

Notapor explorer » 2009-01-07 13:45 @615

[hijo] es un error. Bueno, no, pero sí. No es un error porque Perl "hasta podría admitirlo", pero SEGURO que no es lo que quieres hacer.

Es decir: ¿qué sentido tiene meter una constante entre corchetes?

Los corchetes significa un array por algún lado. Y si lo que queremos es ir guardando un hijo cada vez, yo supongo que querrás poner algo como [$hijo++]. Vamos, una variable nos va colocando cada hijo en una posición dentro del array.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Sombrerero_Loco » 2009-01-08 03:35 @191

Nada... no tiene ningún sentido en absoluto :)
Por eso al final lo he hecho de la forma normal -->
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
push @{ $index{"ID$counter"}{"sons"} }, $serviceref;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Esto me mete el valor perfectamente en el array.
También aprovecho para preguntar si hay alguna forma al estilo de Data:::dumper para poder sacar la info por la salida estándar, hasta ahora lo hacía con bucles foreach() para cada nivel del hash, pero eso es un coñazo.

Tampoco he investigado mucho pero por si las moscas...
De paso, pego aquí el código de cómo lo he hecho finalmente. La verdad que creo que me ha quedado super sencillo y muy condensado.
Darme vuestras impresiones al respecto :)

¡¡Saludos!!

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
 #!/usr/local/bin/perl
use Data::Dumper;
$fichero_xml = "C:\\xmlparser\\xml.xml";
$name = ();
$label = ();
$serviceref = ();
my %index;

##Abrimos fichero
open (FICHERO, "<$fichero_xml");
while (<FICHERO>) {

    if (/<Service>/ .. /<\/Service>/) {                                                 #le indicado que nos busque entre esos tags
        if (/<Name>(.+?)<\/Name>/){                                     #le indicamos que nos busque los datos entre los tag. Este es el padre
                $name = $1;
                $index{$name}{"sid"} = $name;                           #Cargamos en el hash
            if ($index{$name}{"nivel"} < 1) {                           #Si el nivel es menor a 1, lo ponemos a 1
                $index{$name}{"nivel"} = 1                      #(debe de tener nivel 1 como base)
                }
                $index{$name}{"nivel"} = $index{$name}{"nivel"};        #le damos ese valor a ese value del hash

                }
        elsif (/<Label>(.+?)<\/Label>/){
                $label = $1;                                            #si encontramos el valor de label, lo metemos en el hash
                $index{$name}{"nombre"} = $label;
                                }
        elsif (/<ServiceRef>(.+?)<\/ServiceRef>/) {                     #si encontramos este valor, significa que tiene hijos.
           $serviceref = $1;
           push @{ $index{$name}{"hijos"} }, $serviceref;       #Los metemos a un array dentro del hash perteneciente al hijo
           $index{$serviceref}{"nivel"} = $index{$name}{"nivel"} + 1; #le indicamos que para cada hijo del hash, nos coloque el nivel
                                                                                                                                  #del padre + 1

           }

           }
    }

close FICHERO;
warn Dumper %index
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Sombrerero_Loco
Perlero nuevo
Perlero nuevo
 
Mensajes: 42
Registrado: 2008-11-11 11:20 @514

AnteriorSiguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado

cron