0

The below provided list's as contains nested list. I need to fetch the maximum level value in <label> element and insert the value before the <list> element where the attribute appears as 'type="num"'.

For Example:

INPUT:

 <list spitype="num" id="list1">
    <list-item><label>1</label><para></para></list-item>
    <list-item><label>2</label><para></para>
       <list spitype="num" id="list1-1">
      <list-item><label>1</label><para></para></list-item>
      <list-item><label>2</label><para></para></list-item>
      <list-item><label>3</label><para></para></list-item>
       </list></list-item>
    <list-item><label>3</label><para></para></list-item>
    <list-item><label>4</label><para></para></list-item>
    <list-item><label>5</label><para></para></list-item>
 </list>

OUTPUT:

 **<max-val-5/>**
 <list spitype="num" id="list1">
    <list-item><label>1</label><para></para></list-item>
    <list-item><label>2</label><para></para>
         **<max-val-3/>**
     <list spitype="num" id="list1-1">
      <list-item><label>1</label><para></para></list-item>
      <list-item><label>2</label><para></para></list-item>
      <list-item><label>3</label><para></para></list-item>
       </list></list-item>
    <list-item><label>3</label><para></para></list-item>
    <list-item><label>4</label><para></para></list-item>
    <list-item><label>5</label><para></para></list-item>
 </list>

I have wrote this below code however I didn't get the output. The nested list doesn't not covered on this one. Could you please anyone can help on this will be appreciate.

$incnt=~s{(<list(?: |>)[^>]*>((?:(?!<\/list>).)*)<\/list>)}{
my $list=$1; my ($sbpre,$sbmatch,$sbpost,$slmatch,$LblWidthVal) = "";
if($list=~m/<list(?: |>)[^>]*type="num"[^>]*>/g)
{
    $sbpre=$sbpre.$`; $sbmatch=$&; $sbpost=$';
    $slmatch=$1 while($list=~m/<label>([^<>]*)<\/label>/sg);
    $slmatch=~s/[.,:;\(\)\[\]\{\}]*//g;
    $LblWidthVal = "<max-val-$slmatch/>";
    $sbmatch = $LblWidthVal."\n".$sbmatch;
    $sbpre = $sbpre.$sbmatch; $list = $sbpost;
}
if(length $sbpre) {  $list = $sbpre.$sbpost;  }
"$list";}igse;
ssr1012
  • 2,573
  • 1
  • 18
  • 30
  • 2
    https://metacpan.org/pod/XML::LibXML ? – clt60 May 04 '16 at 09:49
  • @jm666: We didn't use any XML module instead of regex only. Might be trying to get output. – ssr1012 May 04 '16 at 09:59
  • 3
    @ssr1012: It's a very bad idea to try to do this with regular expressions, and I doubt if you're going to get anyone to help to to write a solution that way. Why can't you use `XML::LibXML` or `XML::Twig`? – Borodin May 04 '16 at 10:05
  • @Borodin: Till date we didn't use XML modules AND we lack of knowledge in the same. Just we are trying to support the users for avoiding the manual task. Yes I am go through the modules hereafter. Thanks. – ssr1012 May 04 '16 at 10:09
  • 2
    I agree with @Borodin, this is **not** a ask for regexs. Bite the bullet now and learn how to use a XML module. – Henrik supports the community May 04 '16 at 10:29
  • @Henrik: Yes. we have started.... – ssr1012 May 04 '16 at 10:43
  • 2
    Also [Parsing XML with regex](http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags) – Sobrique May 04 '16 at 11:05

1 Answers1

5

While it is possible to add a new XML element with a name of max-val-5 it is highly irregular to put information into the name of an element. It's also illegal to have two root elements in an XML element, so I've wrapped your code in a <root>...</root> element and added a new element that looks like `

This solution uses the XML::Twig module, which I think is a little easier to use than XML::LibXML, especially for outputting XML, and has all of its documentation on a single page

I hope you'll agree that it's very straightforward compared with a regex solution

use strict;
use warnings 'all';

use XML::Twig;
use List::Util 'max';

my $twig = XML::Twig->new( pretty_print => 'indented' );
$twig->parsefile('test.xml');

my $max_label = max $twig->findvalues('//label');

my $max_element = XML::Twig::Elt->new( max => { value => $max_label } );

$max_element->paste( first_child => $twig->root);

$twig->print;

output

<root>
  <max value="5"/>
  <list id="list1" spitype="num">
    <list-item>
      <label>1</label>
      <para></para>
    </list-item>
    <list-item>
      <label>2</label>
      <para></para>
      <list id="list1-1" spitype="num">
        <list-item>
          <label>1</label>
          <para></para>
        </list-item>
        <list-item>
          <label>2</label>
          <para></para>
        </list-item>
        <list-item>
          <label>3</label>
          <para></para>
        </list-item>
      </list>
    </list-item>
    <list-item>
      <label>3</label>
      <para></para>
    </list-item>
    <list-item>
      <label>4</label>
      <para></para>
    </list-item>
    <list-item>
      <label>5</label>
      <para></para>
    </list-item>
  </list>
</root>
Borodin
  • 126,100
  • 9
  • 70
  • 144