-2
<Root>
  <Top Name=" ">
    <Tag name="ALU">
      <in name="PC"/>
      <iodirection name="AB"/>
    </Tag>
    <Tag name=" ">
      <in name="CCB"/>
      <ou name="PC"/>
      <bi name="AB"/>
    </Tag>
    <Tag name=" ">
      <in name="DB"/>
      <ou name="DI"/>
      <bi name="CCB"/>
    </Tag>
    <Tag name=" ">
      <in name="DI"/>
      <ou name="DB"/>
      <bi name="CCB"/>
    </Tag>
  </Top>
</Root>

I'm not a Perl expert, but some simple things are hard for me to figure out and one such task is this. The above XML as you can see the attributes/elements, they're repeated couple of times but for different <in>, <io> and <ou> tags. Now I'm looking to return only the repeated attributes/elements and just print them once.

Example : DI
          DB
          CCB
          AB

My code snippet goes something like this

use strict;

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

$xml_1 = XMLin('./tmp.xml');

my $root_top = $xml_1->{Top};
my $mod_top  = $root_top1->{Tag};
my @mod      = keys %$mod_top;

foreach my $mods ( values %$mod_top ) {

    my $temp = shift(@mod);
    print XST_FILE "$temp u_$temp(\n";

    my $in_mo = $modules->{in};
    my @in_1  = keys %$in_mo;

    foreach my $name_1 ( values %$in_mo ) {

        my $inn = shift(@in_1);

        if ( $inn =~ /\bname\b/ ) {
            print " \.$name_1\($name_1\)\,\n";
        }
        else {
            print " \.$in\($in\)\,\n";
        }
    }

PS: I'd appreciate it if this can be modified only in XML::Simple. Though XML::Simple is discouraged, he's not righteous, but he is the one I'm currently using just to finish this task

Community
  • 1
  • 1
Divox
  • 101
  • 6
  • Your question title is very bad. Please [edit] your question and change the title to say what you want to do. Click-bait does not work here. Also I don't understand what you actually want to do. In addition, it's good that you have `use strict`, but your code will not compile. Please change the code and make it work, and also indent it while you're at it. – simbabque Jan 19 '16 at 13:42
  • 2
    *"My code snippet goes something like this"* Why have you posted *something like* your actual code? What you have shown won't compile, and we stand no chance of helping you if we are working on a problem different from the real one – Borodin Jan 19 '16 at 13:51

2 Answers2

4

Don't use XML::Simple.

#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

use XML::LibXML;
my $xml = 'XML::LibXML'->load_xml(location => shift);

my %names;
$names{ $_->value } = 1 for $xml->findnodes('//*[not(*)]/@name');  # Leaf nodes only.
say for keys %names;
choroba
  • 231,213
  • 25
  • 204
  • 289
  • This includes the `name` attributes of element `iodirection` and prints all values regardless of their frequency – Borodin Jan 19 '16 at 14:23
2

Here's a program that uses XML::LibXML to fulfil the requirement. It uses a single XPath expression to find all the attributes of interest and counts them in hash %names. The subsequent for loop displays all hash keys that have a count greater than 1

use strict;
use warnings 'all';

use XML::LibXML;

my $xml = XML::LibXML->load_xml(IO => \*DATA);

my %names;
++$names{ $_->getValue } for $xml->findnodes('//in/@name | //ou/@name | //bi/@name');

print "$_\n" for grep { $names{$_} > 1 } keys %names;

__DATA__
<Root>
  <Top Name=" ">
    <Tag name="ALU">
      <in name="PC"/>
      <iodirection name="AB"/>
    </Tag>
    <Tag name=" ">
      <in name="CCB"/>
      <ou name="PC"/>
      <bi name="AB"/>
    </Tag>
    <Tag name=" ">
      <in name="DB"/>
      <ou name="DI"/>
      <bi name="CCB"/>
    </Tag>
    <Tag name=" ">
      <in name="DI"/>
      <ou name="DB"/>
      <bi name="CCB"/>
    </Tag>
  </Top>
</Root>

output

DB
PC
DI
CCB
Borodin
  • 126,100
  • 9
  • 70
  • 144