Search code examples
perlxml-twig

How to add attributes in xml twig


I am new to xml::Twig. How to add an attribute and a value from the vmerge tag count with particular vmerge counting? How can I start this? What logic is used in this process?

My script so far:

use XML::Twig;
my $XMLHandler = XML::Twig->new(TwigHandlers =>  {
    },
    pretty_print => 'indented',
);
$XMLHandler->parsefile("sample.xml");
$XMLHandler->print;

Input XML:

<xml>
    <table>
        <tr>
            <column><vmerge value="start"/></column>
            <column></column>
            <column></column>
            <column><vmerge value="start"/></column>
        </tr>
        <tr>
            <column><vmerge/></column>
            <column></column>
            <column></column>
            <column><vmerge/></column>
        </tr>
        <tr>
            <column><vmerge value="start"/></column>
            <column></column>
            <column></column>
            <column><vmerge/></column>
        </tr>
        <tr>
            <column><vmerge/></column>
            <column></column>
            <column></column>
            <column><vmerge/></column>
        </tr>
    </table>
</xml>

I need the output to be as follows:

<xml>
    <table>
        <tr>
            <column rowspan="2"></column>
            <column></column>
            <column></column>
            <column rowspan="4"></column>
        </tr>
        <tr>
            <column></column>
            <column></column>
            <column></column>
            <column></column>
        </tr>
        <tr>
            <column rowspan="2"></column>
            <column></column>
            <column></column>
            <column></column>
        </tr>
        <tr>
            <column></column>
            <column></column>
            <column></column>
            <column></column>
        </tr>
    </table>
</xml>

Solution

  • I think this is what you want:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use XML::Twig;
    my $twig = XML::Twig->new( twig_handlers =>  { table => \&table, },
                               pretty_print => 'indented',
                             )
                        ->parse(\*DATA)
                        ->print;
    
    sub table
      { my( $t, $table)= @_;
        foreach my $vmerge ( $table->descendants( 'vmerge[@value="start"]'))
          { my $span=1;
            my $start_column= $vmerge->parent;
            $vmerge->delete;
            my $column_index= scalar $start_column->prev_siblings( 'column');
    
            my $tr= $start_column->parent( 'tr')->next_sibling( 'tr');
            while( $tr)
              { my $cont_vmerge= $tr->child( $column_index)->first_child( 'vmerge[@value!="start"]');
                if( $cont_vmerge) { $span++; $cont_vmerge->delete; }
                else              { last;                          }
                $tr= $tr->next_sibling( 'tr');
              }
            $start_column->set_att( rowspan => $span);
          }
      }
    
    __DATA__
    <xml>
    <table>
    <tr>
    <column><vmerge value="start"/></column>
    <column></column>
    <column></column>
    <column><vmerge value="start"/></column>
    </tr>
    <tr>
    <column><vmerge/></column>
    <column></column>
    <column></column>
    <column><vmerge/></column>
    </tr>
    <tr>
    <column><vmerge value="start"/></column>
    <column></column>
    <column></column>
    <column><vmerge/></column>
    </tr>
    <tr>
    <column><vmerge/></column>
    <column></column>
    <column></column>
    <column><vmerge/></column>
    </tr>
    </table>
    </xml>