Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

How do I perform a global substitute in an HTML::Element

by GrandFather (Saint)
on Apr 21, 2006 at 02:35 UTC ( [id://544763]=perlquestion: print w/replies, xml ) Need Help??

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

I have a chunk of template HTML in a structure suitable for HTML::Element to use, but it contains place holder text in a number of places that I want to replace with appropriate values at run time. I can manualy access each string that needs to be fixed by navigating the template structure, but that is somewhat fragile. Is there a better way of doing this?

use warnings; use strict; use HTML::TreeBuilder; use Clone qw(clone); my $newHTML = ['div', {class => 'ourobject'}, ['script', {language => 'JavaScript', type => 'text/JavaScript'}, 'embedLabTutorClient("VIEW", "URL", WWW, HHH)', ], ['noscript', ['object', {classid=>"CLSID:ReleaseCLSID", width=>'WWW', height=>'HHH', v +iewastext=>'1'}, ['param', {name=>'ViewSettingsUrl', value=>'URL'}], ['param', {name=>'ViewName', value=>'VIEW'}], ] ] ]; my $objUrl = 'somewhere/object.obj'; my $objView = 'erewhon'; my $objWidth = 255; my $objHeight = 127; my $copy = clone ($newHTML); # Perform 'global' ssubstitutions on $copy here #s/WWW/$objWidth/; #s/HHH/$objHeight/; #s/VIEW/$objView/; #s/URL/$objUrl/; my $element = HTML::Element->new ('root'); $element->push_content ($copy); print $element->as_HTML(undef, ' ', {});

Prints:

<root><div class="ourobject"> <script language="JavaScript" type="text/JavaScript">embedLabTut +orClient("VIEW", "URL", WWW, HHH)</script> <noscript> <object classid="CLSID:ReleaseCLSID" height="HHH" viewastext= +1 width="WWW"> <param name="ViewSettingsUrl" value="URL"> <param name="ViewName" value="VIEW"> </object> </noscript> </div></root>

and I would like:

<root><div class="ourobject"> <script language="JavaScript" type="text/JavaScript">embedLabTut +orClient("erewhon", "somewhere/object.obj", 255, 127)</script> <noscript> <object classid="CLSID:ReleaseCLSID" height="127" viewastext= +1 width="255"> <param name="ViewSettingsUrl" value="somewhere/object.obj" +> <param name="ViewName" value="erewhon"> </object> </noscript> </div></root>

DWIM is Perl's answer to Gödel

Replies are listed 'Best First'.
Re: How do I perform a global substitute in an HTML::Element
by BrowserUk (Patriarch) on Apr 21, 2006 at 04:02 UTC

    Take a look at Data::Rmap. You'll be relying upon the uniqueness of your placeholders, but this seems to produce the output your require:

    use warnings; use strict; use HTML::TreeBuilder; use Clone qw(clone); use Data::Rmap qw[rmap_scalar]; my $newHTML = ['div', {class => 'ourobject'}, ['script', {language => 'JavaScript', type => 'text/JavaScript'}, 'embedLabTutorClient("VIEW", "URL", WWW, HHH)', ], ['noscript', ['object', {classid=>"CLSID:ReleaseCLSID", width=>'WWW', height=>'HHH', v +iewastext=>'1'}, ['param', {name=>'ViewSettingsUrl', value=>'URL'}], ['param', {name=>'ViewName', value=>'VIEW'}], ] ] ]; my $objUrl = 'somewhere/object.obj'; my $objView = 'erewhon'; my $objWidth = 255; my $objHeight = 127; my $copy = clone ($newHTML); # Perform 'global' ssubstitutions on $copy here rmap_scalar{ s/WWW/$objWidth/ } $copy; rmap_scalar{ s/HHH/$objHeight/ } $copy; rmap_scalar{ s/VIEW/$objView/ } $copy; rmap_scalar{ s/URL/$objUrl/ } $copy; my $element = HTML::Element->new ('root'); $element->push_content ($copy); print $element->as_HTML(undef, ' ', {}); __END__ c:\test>junk <root><div class="ourobject"> <script language="JavaScript" type="text/JavaScript">embedLabTut +orClient("erewhon", "somewhere/object.obj", 255, 127)</script> <noscript> <object classid="CLSID:ReleaseCLSID" height=127 viewastext=1 +width=255> <param name="ViewSettingsUrl" value="somewhere/object.obj" +> <param name="ViewName" value="erewhon"> </object> </noscript> </div></root>

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Ah, that was the answer I was looking for. Actually ppm didn't find the package among the repositories I use :(. However is did stimulate me in to looking for other similar modules. For that, thank you! :)

      In the end I used Data::SearchReplace:

      use warnings; use strict; use HTML::TreeBuilder; use Clone qw(clone); use Data::SearchReplace ('sr'); my $newHTML = ['div', {class => 'ourobject'}, ['script', {language => 'JavaScript', type => 'text/JavaScript'}, 'embedLabTutorClient("VIEW", "URL", WWW, HHH)', ], ['noscript', ['object', {classid=>"CLSID:ReleaseCLSID", width=>'WWW', height=>'HHH', v +iewastext=>'1'}, ['param', {name=>'ViewSettingsUrl', value=>'URL'}], ['param', {name=>'ViewName', value=>'VIEW'}], ] ] ]; my $objUrl = 'somewhere/object.obj'; my $objView = 'erewhon'; my $objWidth = 255; my $objHeight = 127; my $copy = clone ($newHTML); sr {SEARCH => 'WWW', REPLACE => $objWidth}, $copy; sr {SEARCH => 'HHH', REPLACE => $objHeight}, $copy; sr {SEARCH => 'VIEW', REPLACE => $objView}, $copy; sr {SEARCH => 'URL', REPLACE => $objUrl}, $copy; my $element = HTML::Element->new ('root'); $element->push_content ($copy); print $element->as_HTML(undef, ' ', {});

      Prints:

      <root><div class="ourobject"> <script language="JavaScript" type="text/JavaScript">embedLabTut +orClient("erewhon", "somewhere/object.obj", 255, 127)</script> <noscript> <object classid="CLSID:ReleaseCLSID" height=127 viewastext=1 +width=255> <param name="ViewSettingsUrl" value="somewhere/object.obj" +> <param name="ViewName" value="erewhon"> </object> </noscript> </div></root>

      DWIM is Perl's answer to Gödel

        You have a solution, but actually, Data::Rmap is pure perl, consisting of a single .PM file. There is really no need to seek a binary distribution. As a minimal installation, just downloading and installing that one file into your site/lib tree will suffice.

        The reason it fails the AS auto-build process is it's dependancy upon Test::Exception. I commented out the 6 tests that use that--they simple check that it handles attempts to modify read-only arguments, and the rest of the tests pass fine.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: How do I perform a global substitute in an HTML::Element
by PodMaster (Abbot) on Apr 21, 2006 at 02:59 UTC
    I can manualy access each string that needs to be fixed by navigating the template structure, but that is somewhat fragile. Is there a better way of doing this?
    Use something like Template, and it becomes as easy as pie.

    Or you could naviate your datastructure, since the structure seems well defined.

    Or use look_down (and friends) to recurse through your $element, and do replacements where appropriate.

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

Re: How do I perform a global substitute in an HTML::Element
by Tanktalus (Canon) on Apr 21, 2006 at 03:02 UTC

    Three possibilities off the top of my head.

    First, do your substitutions on the string returned from as_HTML. A little error-prone, but probably not that bad.

    Second, stop using HTML::Element. Use HTML::Template instead. You could put the template in your __DATA__ section.

    Third, use Template Toolkit - instead of having WWW and HHH, etc., have [%WWW%] and [%HHH%], etc. And then you can feed the as_HTML output into Template Toolkit to do the next level of modification. You can't easily do this with HTML::Template only because having <tmpl_var name="HHH"> instead of just HHH would get modified by HTML::Element to look like &lt;tmpl_var name="HHH"&gt; inside the tags, and that would defeat it. TT2 could handle that largely because it uses different delimiters.

    I realise that you are probably looking for a way to traverse the data structure. That's just not the way I'm looking at the problem - I have a different box to think inside of ;-}

      This is in the context of code that is editing existing HTML to replace object elements with a chunk of script.

      Option 1 simply won't work because many parameters need to be replaced with different values in different contexts.

      Options 2 and 3 probably don't make sense in this context. XML::Twig would be great, but XHTML these pages are not!

      Currently I'm doing it by navigating the structure, but that is rather fragile!


      DWIM is Perl's answer to Gödel
Re: How do I perform a global substitute in an HTML::Element
by mojotoad (Monsignor) on Apr 21, 2006 at 21:14 UTC
    You might be interested in HTML::Seamstress. From what I understand, this type of global replacement is the basis for the methodology of that class.

    Cheers,
    Matt

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://544763]
Approved by Zaxo
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2024-04-19 23:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found