Akku has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I am trying to add hyperlink to some lines of MS doc. But to first line of the document hyperlink is applied. By applying sleep function I have noticed that it changes hyperlink content of first line to other link. It does'nt apply the link to other lines

I am providing the tested code.

Please keep cursor on generated ms doc, while script generates the doc, changing of hyperlink content on first line will be clearly visible.

use warnings;
use Win32::OLE;
my $word = Win32::OLE->new('Word.Application') or die $!;
$word->{'Visible'} = 1;
my $document = $word->Documents->Add;
my $selection = $word->Selection;
%hash =('This is a test line' => '1', 'This is second test Line' => '1', 'This is the third line' => '1');

my ($c, $start, $end, $r) = (2, 0, 0, );
foreach $elemetns(keys %hash)
{
    $end1 = length($elemetns);
    print "$elemetns $start $end1\n";
    $selection->TypeText($elemetns);
    #$r = ();
    $r = $document->Range($start, $end1);
    $selection->Font->{Size} = 12;
    $selection->Font->{ColorIndex} = $c++;
$selection->Hyperlinks->Add({ Anchor => $r, Address => "$elemetns" }) or die "I am unable to do it";

    $selection -> TypeParagraph;
    sleep (1);
}
undef $word;

Thanks

Replies are listed 'Best First'.
Re: Add hyperlink to paticular lines of MS doc
by kcott (Archbishop) on Dec 05, 2013 at 04:36 UTC

    G'day Akku,

    I'm not in a position to test this: no Perl on MSWin; no MS Word; no Win32::OLE. However, I see some anomalies in your code which might be the cause of the problem.

    • You declare $end but then use $end1 elsewhere in your code.
    • You set $start to zero and never change it.

    Without changing any other parts of your code, would your for loop code be better as something closer to this:

    my ($c, $start, $end) = (2, 0, 0); foreach $elemetns(keys %hash) { $start = $end; $end += length $elemetns; ... my $r = $document->Range($start, $end); ... }

    [Note: The += is a guess; it depends on how Range() works; just = might be correct.]

    Unrelated to your current issue but possibly a source of confusion or errors later on:

    • I see no reason for %hash. You only use its keys in the code shown and the name is meaningless. I'd suggest my @elements = (...); would be a better choice here.
    • $elemetns is probably a poor choice. It suggests plural although it's a scalar value only ever holding a single string. It also looks like a misspelling of element which someone (possibly you) may spell correctly later in your script development. I think $element would be a better choice.

    So, I'd suggest these changes:

    ... my @elements = ( 'This is a test line', 'This is second test Line', 'This is the third line', ); ... my ($c, $start, $end) = (2, 0, 0); for my $element (@elements) { $start = $end; $end += length $element; ... my $r = $document->Range($start, $end); ... }

    $c and $r are also problematical. They're basically meaningless names which conveyed nothing when I first encountered them. Perhaps $colour_index and $range would be better names.

    Also, you assign $c = 2. What does '2' mean? While you may know today, will you when you revisit this code at some later time. Will the next maintainer know? Either use a meaningfully named constant or add a comment explaining what '2' refers to. As a general rule, arbitrary constant numbers popping in pieces of code are difficult to understand (without doing extra research which shouldn't be necessary) and are error-prone.

    -- Ken

Re: Add hyperlink to paticular lines of MS doc
by VincentK (Beadle) on Dec 05, 2013 at 15:08 UTC

    Hi Akku.

    I used the following Microsoft pages to help me modify your code.

    http://msdn.microsoft.com/en-us/library/xa46twee.aspx

    http://msdn.microsoft.com/en-us/library/tx0x9x4d.aspx

    This issue with your code was that your range was not selected for the current sentence that was written out.

    I hope this helps.

    use strict; use warnings; use Win32::OLE; my $word = Win32::OLE->new('Word.Application') or die $!; my $document = $word->Documents->Add; my $selection = $word->Selection; $word->{'Visible'} = 1; my @DATA_array = ( 'This is a test line' , 'This is second test Line' , 'This is the third line' ); my ($ColorIndex_iter, $start, $end, $current_sentence_iter) = (2, 0, 0 +, 1); foreach my $elements (@DATA_array) { $selection->TypeText($elements); print "$elements $start ".length($elements)."\n"; $selection->Font->{Size} = 12; $selection->Font->{ColorIndex} = $ColorIndex_iter; $selection->Hyperlinks->Add({ Anchor => $document->Range->Sentence +s($current_sentence_iter), Address => $elements }) or die "I am unabl +e to do it"; $selection -> TypeParagraph; $current_sentence_iter++; sleep (1); } undef $word;

      Hi VincentK,

      Your solution has helped me a lot for adding links on new MS Doc

      I tried to add hyperlink to existing document by opening it, then selecting the text on which i want to add hyperlink. Selection of sentence is visible, but giving error "Can't call method "Hyperlinks" on an undefined value" while applyinh hyperlink. I want to add hyperlink on docx file sentence '1.1.1lc_base_dpp0'

      I am not understanding why it is not applying hyperlink on selected sentence

      Docx file is having following content

      Line 1

      Line2

      Line3

      Line4

      1.1.1lc_base_dpp0

      Line2

      I am providing my sample code

      use strict;
      use Win32::OLE;
      use Win32::OLE::Enum;
      use Win32::OLE qw(in);
      use Data::Dumper;
      use Win32::OLE::Const 'Microsoft Word';
      my $Word = Win32::OLE->GetActiveObject('Word.Application');
      unless ($Word) { $Word = Win32::OLE->new('Word.Application', sub {$_[0 +]->Quit;}) or die "oops\n"; } <code>$Word->{visible} = 1;

      my $file_name_for_mod_spec = "D:/Perl_programs/test1.docx";
      my $generated_doc2 = $Word-> Documents->Open("$file_name_for_mod_spec");
      my $generated_doc_paragraphs1 = $generated_doc2->Paragraphs;
      my $generated_doc_total_paragraphs1 = $generated_doc_paragraphs1->Count ();
      for my $p11 (1..$generated_doc_total_paragraphs1)
      {
              my $template_paragraph1 = $generated_doc_paragraphs1->Item ($p11);
              my $template_text = $template_paragraph1->{Range}->{Text};
              if ($template_text =~ m/1.1.1lc_base_dpp0/gi)
              {
                  my $mod_selection = $template_paragraph1->{Range}->Select();
                  sleep(5);
                  print " 11111 $p11 $template_text \n";
                  $mod_selection->Hyperlinks->Add({ Anchor => $generated_doc_paragraphs1->Range->Sentences($p11), Address => "http://perlmonks.org" }) or die "I am unable to do it";
                  sleep(5);
              }
      }
      $generated_doc2->Close();
      $Word->Quit();
      undef $generated_doc2;
      undef $Word;