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

Dear Monks,

Using the Template Toolkit, I'm creating templates in an XML format to create XLS files. Of course, I'm using the TT instructions such as  "[% FOREACH ... %], [% END %], [% IF %]". My objective is to create a user friendly HTML view of a template so users can consult it. I want to retrieve sheet names, cell contents and TT instructions.

I'm looking for advice on two different topics. First I was thinking about XML::LibXML for the XML parsing part. Is it a good choice for this task ? Second, since TT instructions won't be recognized as XML content, how should I parse the mixed content to obtain a result respecting the template logic ? (line order)

Post edit : After my reply to Marto, I thought I should add some info to my post.

The source data is XML with TT instructions in the file. The XML is intended to create and XLS file.Below is an extract

<?xml version="1.0" encoding="ISO-8859-1"?> <workbook> <worksheet name="[% config.template %]"><format color="black"> [% FOREACH host IN hosts %] <row><bold><format color="white" size="14" bg_color="blue"><cell w +idth="60" text="Configuring de : [% host.name %]" /></format></bold>< +/row> <row /> [% FOREACH int IN host.interfaces %] <row><cell text="interface ip-bundle [% int.bundle %].[% int.subBu +ndle %]" /></row> [% FOREACH ip IN int.secondaries %] <row><cell text=" ip address [% ip.ipAddress %] [% ip.subnetMask % +] [% bits(ip.ipAddress,ip.subnetMask) %] secondary" /></row> [% END %] <row><cell text="!"/></row> [% END %] <row /> <row><bold><format color="white" size="14" bg_color="blue"><cell t +ext="END OF : [% host.name %]" /></format></bold></row> <row /><row /><row /> [% END %] </format> </worksheet> </workbook>
So what I want to do, is extract both "cell text" and TT instructions to recreate the content in HTML format. Problem is, how should I parse the file so that I can retrieve XML with XML::LibXML & TT instruction lines at the same time ? Like I said, my objective is to display the template to the users. Creating the XLS file is not a problem. I want to show network engineers how the template is built without giving access to the .tt file.

Cheers ! Luc

Replies are listed 'Best First'.
Re: XML Parsing in a "mixed content" file
by marto (Cardinal) on Jan 11, 2019 at 16:05 UTC

    You don't say what your source data is, so this may not be what you're looking for, but have you considered using something like Excel::Writer::XLSX to create the Excel file, and something like Datatables (via DataTables) for the user preview for consultation?

    Update: Fixed module name.

      Hi Marto, the source data is XML with TT instructions in the file.

      The XML is intended to create and XLS file.Below is an extract

      <?xml version="1.0" encoding="ISO-8859-1"?> <workbook> <worksheet name="[% config.template %]"><format color="black"> [% FOREACH host IN hosts %] <row><bold><format color="white" size="14" bg_color="blue"><cell w +idth="60" text="Configuring de : [% host.name %]" /></format></bold>< +/row> <row /> [% FOREACH int IN host.interfaces %] <row><cell text="interface ip-bundle [% int.bundle %].[% int.subBu +ndle %]" /></row> [% FOREACH ip IN int.secondaries %] <row><cell text=" ip address [% ip.ipAddress %] [% ip.subnetMask % +] [% bits(ip.ipAddress,ip.subnetMask) %] secondary" /></row> [% END %] <row><cell text="!"/></row> [% END %] <row /> <row><bold><format color="white" size="14" bg_color="blue"><cell t +ext="END OF : [% host.name %]" /></format></bold></row> <row /><row /><row /> [% END %] </format> </worksheet> </workbook>
      So what I want to do, is extract both "cell text" and TT instructions to recreate the content in HTML format. Problem is, how should I parse the file so that I can retrieve XML with XML::LibXML & TT instruction lines at the same time ? Like I said, my objective is to display the template to the users. Creating the XLS file is not a problem. I want to show network engineers how the template is built without giving access to the .tt file.

        "the source data is XML with TT instructions in the file."

        That's not really the source data, since you need to create the XML. Your solution creates an XML file using Templates, I was asking what the source data was, since you obviously have it in a perl script, you could use this data to feed both the preview (one method described above) and create the Spreadsheet (Excel::Writer::XLSX). Seems illogical to create a file in a certain format only to parse it back into perl just to present a preview.

Re: XML Parsing in a "mixed content" file
by poj (Abbot) on Jan 11, 2019 at 18:21 UTC
    recreate the content in HTML format

    Is that a static html file or dynamically with a script (like cgi) ?

    Update - Are you looking for something as simple as this ?

    #!perl use strict; use HTML::Entities; open OUT,'>', 'template.html' or die "$!"; print OUT '<html><body><pre>'; while (<DATA>){ print OUT encode_entities($_); } print OUT '</pre></html>'; __DATA__ <?xml version="1.0" encoding="ISO-8859-1"?> <workbook> <worksheet name="[% config.template %]"><format color="black"> [% FOREACH host IN hosts %] <row><bold><format color="white" size="14" bg_color="blue"><cell w +idth="60" text="Configuring de : [% host.name %]" /></format></bold>< +/row> <row /> [% FOREACH int IN host.interfaces %] <row><cell text="interface ip-bundle [% int.bundle %].[% int.subBu +ndle %]" /></row> [% FOREACH ip IN int.secondaries %] <row><cell text=" ip address [% ip.ipAddress %] [% ip.subnetMask % +] [% bits(ip.ipAddress,ip.subnetMask) %] secondary" /></row> [% END %] <row><cell text="!"/></row> [% END %] <row /> <row><bold><format color="white" size="14" bg_color="blue"><cell t +ext="END OF : [% host.name %]" /></format></bold></row> <row /><row /><row /> [% END %] </format> </worksheet> </workbook>
    poj

      Hello poj, this would be static. I have built different templates and I want to display them in an elegant manner through a web page.

      What you suggested is nice, but what I really wanted to do (mostly) was extract content from "cell.text" ( and some other tags ) + the TT instructions and reformat the whole as an HTML document and apply some format. And I'm really thinking it would be easier to just write a regex for the purpose and recreate an HTML document from capture groups.

Re: XML Parsing in a "mixed content" file
by haukex (Archbishop) on Jan 11, 2019 at 16:47 UTC

    If by "mixed content" you mean e.g. <node>foo<bar>quz</bar>baz</node>, then yes, I personally would definitely reach for XML::LibXML. Many of the modules that map XML to Perl data structures aren't able to properly represent or round-trip such mixed content XML.

      By mixed content I meant XML + TT directives (the template itself), since I'm building an XML from a TT template.
Re: XML Parsing in a "mixed content" file
by Veltro (Hermit) on Jan 11, 2019 at 22:06 UTC

    Why don't you just fill the template with template strings? What I mean is you fill up the storage holder of the template with stuff like:

    # This is free hand, please ignore typos: my $templateContents = { hosts => { name = '[% host.name %]', }, ... }

    I'm sure that you can find something that will nicely display the resulting XML file on a HTML page

    edit: I have created a better example below

    use strict ; use warnings ; use Template ; my $file = 'template.xml.tt'; my $vars = { hosts => [ { name => "[% host.name %]", } ], }; my $template = Template->new(); $template->process($file, $vars) || die "Template process failed: ", $template->error(), "\n" ;

    I took only a part of your example template file:

    <?xml version="1.0" encoding="ISO-8859-1"?> <workbook> <worksheet name="[% config.template %]"><format color="black"> [% FOREACH host IN hosts %] <row><bold><format color="white" size="14" bg_color="blue"><cell w +idth="60" text="Configuring de : [% host.name %]" /></format></bold>< +/row> [% END %] </worksheet> </workbook>

    Of course it leaves out each of the FOREACH statements, but it basically gives you the freedom to fill in anything you want to show to your users, to show them which fields are automatically generated for them

    The output would look like this:

    <workbook> <worksheet name=""><format color="black"> <row><bold><format color="white" size="14" bg_color="blue"><cell w +idth="60" text="Configuring de : [% host.name %]" /></format></bold>< +/row> </worksheet> </workbook>