MsOffice-Word-Template-2.05000755000000000000 014676057567 16173 5ustar00unknownunknown000000000000MsOffice-Word-Template-2.05/Build.PL000444000000000000 231214631242420 17571 0ustar00unknownunknown000000000000use strict; use warnings; use Module::Build; Module::Build->VERSION('0.4004'); my $builder = Module::Build->new( module_name => 'MsOffice::Word::Template', license => 'artistic_2', dist_author => q{DAMI }, dist_version_from => 'lib/MsOffice/Word/Template.pm', release_status => 'stable', configure_requires => { 'Module::Build' => '0.4004', }, test_requires => { 'Test::More' => '0', }, requires => { perl => '5.24.0', 'Carp' => undef, 'Moose' => undef, 'MooseX::StrictConstructor' => undef, 'MooseX::AbstractMethod' => undef, 'MsOffice::Word::Surgeon' => '2.06', 'Template::AutoFilter' => undef, 'namespace::clean' => undef, }, recommends => { 'Barcode::Code128' => undef, 'Image::PNG::QRCode' => undef, 'GD' => undef, }, add_to_cleanup => [ 'MsOffice-Word-Template-*' ], meta_merge => { resources => { repository => 'https://github.com/damil/MsOffice-Word-Template', } }, ); $builder->add_build_element('docx'); $builder->create_build_script(); MsOffice-Word-Template-2.05/Changes000444000000000000 162114676057313 17610 0ustar00unknownunknown000000000000Revision history for MsOffice-Word-Template 2.05 28.09.2024 - consistent licensing declarations : artistic 2 in all files 2.04 09.06.2024 - recommends GD, necessary for barcode generation in addition to Barcode::Code128 2.03 08.06.2024 - forgot dependency on Barcode::Code128 2.02 06.06.2024 - fix MANIFEST forgot one module in v2.01 2.01 06.06.2024 - support for inserting fragments from other .docx files - tests for barcode generation - refactoring : methods moved to the back-end class 'Engine' - doc: highlighting help for LibreOffice users 2.0 01.05.2022 - general refactoring - first support for barcodes - entity encoding 1.02 28.03.2022 - support for bookmarks, hyperlinks and Word fields 1.01 11.01.2021 - Template Toolkit is no longer hardwired in; other templating systems can be passed as parameters 1.0 13.12.2020 Initial release MsOffice-Word-Template-2.05/MANIFEST000444000000000000 75314630375060 17423 0ustar00unknownunknown000000000000Build.PL Changes examples/describe_moose_class.pl examples/describe_moose_class.tmpl.docx lib/MsOffice/Word/Template.pm lib/MsOffice/Word/Template/Engine.pm lib/MsOffice/Word/Template/Engine/Mustache.pm lib/MsOffice/Word/Template/Engine/TT2.pm lib/MsOffice/Word/Template/Engine/TT2/Provider.pm MANIFEST This list of files README.md t/etc/barcode_template.docx t/etc/mustache_template.docx t/etc/tt2_template.docx t/etc/inserted_doc.docx t/barcode.t t/mustache.t t/tt2.t META.yml META.json MsOffice-Word-Template-2.05/META.json000444000000000000 435614676057567 17761 0ustar00unknownunknown000000000000{ "abstract" : "generate Microsoft Word documents from Word templates", "author" : [ "DAMI " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4234", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "MsOffice-Word-Template", "prereqs" : { "configure" : { "requires" : { "Module::Build" : "0.4004" } }, "runtime" : { "recommends" : { "Barcode::Code128" : "0", "GD" : "0", "Image::PNG::QRCode" : "0" }, "requires" : { "Carp" : "0", "Moose" : "0", "MooseX::AbstractMethod" : "0", "MooseX::StrictConstructor" : "0", "MsOffice::Word::Surgeon" : "2.06", "Template::AutoFilter" : "0", "namespace::clean" : "0", "perl" : "v5.24.0" } }, "test" : { "requires" : { "Test::More" : "0" } } }, "provides" : { "MsOffice::Word::Template" : { "file" : "lib/MsOffice/Word/Template.pm", "version" : "2.05" }, "MsOffice::Word::Template::Engine" : { "file" : "lib/MsOffice/Word/Template/Engine.pm", "version" : "2.05" }, "MsOffice::Word::Template::Engine::Mustache" : { "file" : "lib/MsOffice/Word/Template/Engine/Mustache.pm", "version" : "2.05" }, "MsOffice::Word::Template::Engine::TT2" : { "file" : "lib/MsOffice/Word/Template/Engine/TT2.pm", "version" : "2.05" }, "MsOffice::Word::Template::Engine::TT2::Provider" : { "file" : "lib/MsOffice/Word/Template/Engine/TT2/Provider.pm", "version" : "2.05" } }, "release_status" : "stable", "resources" : { "license" : [ "http://www.perlfoundation.org/artistic_license_2_0" ], "repository" : { "url" : "https://github.com/damil/MsOffice-Word-Template" } }, "version" : "2.05", "x_serialization_backend" : "JSON::PP version 4.16" } MsOffice-Word-Template-2.05/META.yml000444000000000000 276414676057567 17612 0ustar00unknownunknown000000000000--- abstract: 'generate Microsoft Word documents from Word templates' author: - 'DAMI ' build_requires: Test::More: '0' configure_requires: Module::Build: '0.4004' dynamic_config: 1 generated_by: 'Module::Build version 0.4234, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: MsOffice-Word-Template provides: MsOffice::Word::Template: file: lib/MsOffice/Word/Template.pm version: '2.05' MsOffice::Word::Template::Engine: file: lib/MsOffice/Word/Template/Engine.pm version: '2.05' MsOffice::Word::Template::Engine::Mustache: file: lib/MsOffice/Word/Template/Engine/Mustache.pm version: '2.05' MsOffice::Word::Template::Engine::TT2: file: lib/MsOffice/Word/Template/Engine/TT2.pm version: '2.05' MsOffice::Word::Template::Engine::TT2::Provider: file: lib/MsOffice/Word/Template/Engine/TT2/Provider.pm version: '2.05' recommends: Barcode::Code128: '0' GD: '0' Image::PNG::QRCode: '0' requires: Carp: '0' Moose: '0' MooseX::AbstractMethod: '0' MooseX::StrictConstructor: '0' MsOffice::Word::Surgeon: '2.06' Template::AutoFilter: '0' namespace::clean: '0' perl: v5.24.0 resources: license: http://www.perlfoundation.org/artistic_license_2_0 repository: https://github.com/damil/MsOffice-Word-Template version: '2.05' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' MsOffice-Word-Template-2.05/README.md000444000000000000 3213763621441 17522 0ustar00unknownunknown000000000000# MsOffice-Word-Template MsOffice-Word-Template-2.05/examples000755000000000000 014676057567 20011 5ustar00unknownunknown000000000000MsOffice-Word-Template-2.05/examples/describe_moose_class.pl000444000000000000 123114233544537 24632 0ustar00unknownunknown000000000000use 5.24.0; use strict; use warnings; use MsOffice::Word::Template; use Module::Load; # path to the template file my $template_file = "describe_moose_class.tmpl.docx"; # Moose class to be described : first arg on the command line my $class = shift // "MsOffice::Word::Template"; # load that class and get its metaclass; load $class; my $metaclass = $class->meta; # open the template and generate the class description my $template = MsOffice::Word::Template->new($template_file); my $new_doc = $template->process({meta => $metaclass}); my $filename = ($class =~ s/::/_/gr) . "_description.docx"; $new_doc->save_as($filename); warn "generated $filename\n"; MsOffice-Word-Template-2.05/examples/describe_moose_class.tmpl.docx000444000000000000 3144113765475653 26170 0ustar00unknownunknown000000000000PK!ߤlZ [Content_Types].xml (n0EUb袪*>-R{VǼQU l"%33Vƃښl w%=^i7+-d&0A6l4L60#ÒS OX*V$z33%p)O^ 5}nH"dsXgL`|ԟ|Prۃs?PWtt4Q+"wa|T\y,NU%-D/ܚXݞ(K/4Vm^urw2NP0ŮVw5j o7o:>S!?p8JX[d0KDEVKc2P,ũa].ﰘsYҡ+(!O>zPK!?|6(word/document.xmlZ[oH~_i+m NJ]%FjQ}0l`͌㸿~NQs=@B=&1u ";r'w#] T06i.'plNSf^=;LkZ| !G#8Co}j 20΍Q(x*!kLxF6|qC{l!a 'q>aEl+V&AU[f9$E@xaӠ- UB<~nZbr~dWW#Zf dG4cNVI)4>R bAtBcYv,`Eޒ`z3P0+smqi}ʳ ;{цn̳}iz<4k9.YED4 t`ZʫVJVq(pfU Q^FaV vtC~s"e e`ThNI:iKmQС>w8|afRsUS#Q`ۯ0\-}",`b#[@R+ 4D;0پ0s[oP adnT{౑j_n1_볱Q pWJnVʼn YB?wD (ylfGm'8Y\\, u%c[mY.Sb+?j" 2Q?m_LR-2L>0r#}|%Ynbv-J79a,[>NPK!+/word/theme/theme1.xmlYM7;3X N&!IQgՌH]%9R(zkh襇643d]u a}}G+ aFIvc[0 HҨk9UڶEHCI R];, }Jw@׎T4̀^"S x5aNWӬ&=;9ڻ!RFEC& 6άc6($'?{0lb7]aե]¿`asO@\T^U@y{4j^X<5h/cgI^bs rz%((=ZC;^ᗳ]@&_3;;j UUVWnMk-I6\PjN@q>h!kE1_xSʛ3r$#v P󦀮5 > 24e]SV /_8{og={H#_s_k3W??=h}g/򯟞 U!J n6I qf1@E/(H1,78͸\Wg5q6c'p'qNXjfid<WA9{T*; GQVQab12 VFg1ajr#jM gl6x0oʧSnز-e;?Xl-e-%a&$t Vx 9X,W, ~ܜ_oP)/Lo >azu;H(M',py˹,SXj\ Y5﹆`ڵ'VȋɔB7Ү"GYe@&'(k]MNj;J{_jdeY}cBfAXc~V#q6ӂ R$'̵  *5)RHīx1-v{ /3-g@iWKkjN랸(%^'^`)!A55v1Rh lWԪ@ܱ)p_)$>b&5~0$}KHzxEtg\; \mʿp^ONQEq\k`^R@5*(Fg(qZPS#W怙. ~$P549SSW?ZC r  pgM%t)jy{:m1N0P)]ԝ:S;ǬJE@x- `ݹF0$c:%͖ +P~1RUX"t?`TAe[seXm;LvyzWe$246پQddIp܃E`8v8* as9An0YX/bT/d'xϜTh v6|6X1Y9&_4g6~.3UPa{H2@qX QN ZQEFR Ug2\'Wq2ޞY]y,.w(#d\FуQsBh cxZ䡺,nLJJϷI8i85lL,W/9VsA"[$ʐGLf~Q".q?ۻ*LA^j2 pPK!vI@word/webSettings.xmlJ1;l-t[xA}4mLȤn;U/-d>gf==FV}4y9֊k(Bz1uu'(E~%rRRm -!%RF[6&[_f\US}d) wpKnKo2)'ֺS:er,y0|yh}aFW .S[8QOIO~y0e8 VMlWA$d*z.+T 94R-އ`VHÕ_>^qֽ|"h(slէ aQ u%vZYPV6Tۭ2-h1Kmwo*A7* icFY==MYv"pꨂt[So^ u"gT֍orGfdRc@7.;;'G` Jӊ9L"bG^hFCu;j_Gw1UPK!4^|docProps/core.xml (MO0 H*'8t@SuL;M[H-I$[Oڮ;pǯ7I'{GІrQ<`\n'm=3HFBU`4IJha r0S&jv֪cCw 9BЂX-VpX%XkA_,h/:oŐi G!0W/Rp[)vŞ>ރeYʸA!X.^\^Q@Yhb!K%t9|}qj ٌ-Ayw쪵{B345 Gإ{ T]4yG(j>OώSIkWyg9ʢ 0xFCg"(O1 xVjIsӈkq2票^#q2mɍnB dQ)7i®YѴt"}Eo6o6H{GSq]>t$D2շ i\M'W|L_#tQG,^jh:xߪj[51ɆXR@Ʊͱ ͱh ͱHͱ(ͱ:cc4NC[6}sw>q'|7ݞݸ۳w{s˥Vp#eUTt凧&=*LD<y{h* 6qE(h^ˈĴK*hR* -\o,F"zI u@yD<uBBwoeJA"'g?!Yk_h@c "C4Ri Ӹk Ӹq3vXc:yiƜ3 W:+ݍm33>洚k]C\5KڢW$I`5o>eZ]g"& E6ȼɠ!?r̷mXe:+yAzeG?ieM,Gx'#sXkJ~]2HzE2kbT_]P> K]BX[A\ Zj`xӜ w"8}tNi90ɔ$y"e&K9T~/ NDv'hyKN=$YڒyI! սXaV,T^ })r}Q/u?eB 7~)-=I1%Tgíxw|gxN{޲UW&pweU̶75,]fhĊ(|povJey0yrJnY m~huڲp?ug (; ڲ+%4 a";#';e>}?1ISW=^DʜEm["P>?Ӥ%,f C-9oZ"o/қ`չߗ}`KZM)r:}ia @_, init_arg => undef, lazy => 1, builder => "_$attr")} use namespace::clean -except => 'meta'; our $VERSION = '2.05'; #====================================================================== # ATTRIBUTES #====================================================================== # constructor attributes for interacting with MsWord # See also BUILDARGS: the constructor can also take a "docx" arg # that will be automatically translated into a "surgeon" attribute has 'surgeon' => (is => 'ro', isa => 'MsOffice::Word::Surgeon', required => 1); has 'data_color' => (is => 'ro', isa => 'Str', default => "yellow"); has 'control_color' => (is => 'ro', isa => 'Str', default => "green"); has 'part_names' => (is => 'ro', isa => 'ArrayRef[Str]', lazy => 1, default => sub {[keys shift->surgeon->parts->%*]}); has 'property_files'=> (is => 'ro', isa => 'ArrayRef[Str]', default => sub {[qw(docProps/core.xml docProps/app.xml docProps/custom.xml)]}); # constructor attributes for building a templating engine has 'engine_class' => (is => 'ro', isa => 'Str', default => 'TT2'); has 'engine_args' => (is => 'ro', isa => 'ArrayRef', default => sub {[]}); # attributes lazily constructed by the module -- not received through the constructor has_inner 'engine' => (is => 'ro', isa => 'MsOffice::Word::Template::Engine'); #====================================================================== # BUILDING INSTANCES #====================================================================== # syntactic sugar for supporting ->new($surgeon) instead of ->new(surgeon => $surgeon) around BUILDARGS => sub { my $orig = shift; my $class = shift; # if there is a unique arg without any keyword ... if ( @_ == 1) { # if the unique arg is an instance of Surgeon, it's the "surgeon" parameter unshift @_, 'surgeon' if $_[0]->isa('MsOffice::Word::Surgeon'); # if the unique arg is a string, it's the "docx" parameter unshift @_, 'docx' if $_[0] && !ref $_[0]; } # translate the "docx" parameter into a "surgeon" parameter my %args = @_; if (my $docx = delete $args{docx}) { $args{surgeon} = MsOffice::Word::Surgeon->new(docx => $docx); } # now call the regular Moose method return $class->$orig(%args); }; #====================================================================== # LAZY ATTRIBUTE CONSTRUCTORS #====================================================================== sub _engine { my ($self) = @_; # instantiate the templating engine my $engine_class = $self->engine_class; my $engine; my @load_errors; CLASS: for my $class ("MsOffice::Word::Template::Engine::$engine_class", $engine_class) { eval "require $class; 1" or push @load_errors, $@ and next CLASS; $engine = $class->new(word_template => $self, $self->engine_args->@*) and last CLASS; } $engine or die "could not load engine class '$engine_class'", @load_errors; return $engine; } #====================================================================== # PROCESSING THE TEMPLATE #====================================================================== sub process { my ($self, $vars) = @_; # create a clone of the original my $new_doc = $self->surgeon->clone; # process each package part foreach my $part_name ($self->part_names->@*) { my $new_doc_part = $new_doc->part($part_name); my $new_contents = $self->engine->process_part($part_name, $new_doc_part, $vars); $new_doc_part->contents($new_contents); } # process the property files (core.xml, app.xml. custom.xml -- if present in the original word template) foreach my $property_file ($self->property_files->@*) { if ($self->surgeon->zip->memberNamed($property_file)) { my $new_contents = $self->engine->process($property_file, $vars); $new_doc->xml_member($property_file, $new_contents); } } return $new_doc; } 1; __END__ =encoding ISO-8859-1 =head1 NAME MsOffice::Word::Template - generate Microsoft Word documents from Word templates =head1 SYNOPSIS my $template = MsOffice::Word::Template->new($filename); my $new_doc = $template->process(\%data); $new_doc->save_as($path_for_new_doc); =head1 DESCRIPTION =head2 Purpose This module treats a Microsoft Word document as a template for generating other documents. The idea is similar to the "mail merge" functionality in Word, but with much richer possibilities. The whole power of a Perl templating engine can be exploited, for example for =over =item * dealing with complex, nested datastructures =item * using control directives for loops, conditionals, subroutines, etc. =item * defining custom data processing functions or macros =back Template authors just use basic highlighing in MsWord to mark the templating directives : =over =item * fragments highlighted in B are interpreted as I directives, i.e. the template result will be inserted at that point in the document, keeping the current formatting properties (bold, italic, font, etc.). =item * fragments highlighted in B are interpreted as I directives that do not directly generate content, like loops, conditionals, etc. Paragraphs or table rows around such directives are dismissed, in order to avoid empty paragraphs or empty rows in the resulting document. =back The syntax of data and control directives depends on the backend templating engine. The default engine is the L; other engines can be specified as subclasses -- see the L section below. =head2 Status This distribution is a major refactoring of the first version, together with a refactoring of L. New features include support for headers and footers, for metadata and for image insertion. The internal object-oriented structure has been redesigned. This module has been used successfully for a pilot project in my organization, generating quite complex documents from deeply nested datastructures. However it has not been used yet at large scale in production, so it is quite likely that some youth defects may still be discovered. If you use this module, please keep me informed of your difficulties, tricks, suggestions, etc. =head1 METHODS =head2 new my $template = MsOffice::Word::Template->new($docx); # or : my $template = MsOffice::Word::Template->new($surgeon); # an instance of MsOffice::Word::Surgeon # or : my $template = MsOffice::Word::Template->new(docx => $docx, %options); In its simplest form, the constructor takes a single argument which is either a string (path to a F document), or an instance of L. Otherwise the constructor takes a list of named parameters, which can be =over =item docx path to a MsWord document in F format. This will automatically create an instance of L and pass it to the constructor through the C keyword. =item surgeon an instance of L. This is a mandatory parameter, either directly through the C keyword, or indirectly through the C keyword. =item data_color the Word highlight color for marking data directives (default : yellow) =item control_color the Word highlight color for marking control directives (default : green). Such directives should produce no content. They are treated outside of the regular text flow. =item part_names an arrayref to the list of package parts to be processed as templates within the C<.docx> ZIP archive. The default list is the main document (C), together with all headers and footers found in the ZIP archive. =item property_files an arrayref to the list of property files (i.e. metadata) to be processed as templates within the C<.docx> ZIP archive. For historical reasons, MsWord has three different XML files for storing document properties : C, C and C : the default list contains those three files. Supply an empty list if you don't want any document property to be processed. =back In addition to the attributes above, other attributes can be passed to the constructor for specifying a templating engine different from the default L. These are described in section L below. =head2 process my $new_doc = $template->process(\%data); $new_doc->save_as($path_for_new_doc); Processes the template on a given data tree, and returns a new document (actually, a new instance of L). That document can then be saved using L. =head1 AUTHORING TEMPLATES =head2 Textual content A template is just a regular Word document, in which the highlighted fragments represent templating directives. The data directives, i.e. the "holes" to be filled must be highlighted in B. Such zones must contain the names of variables to fill the holes. If the template engine supports it, names of variables can be paths into a complex datastructure, with dots separating the levels, like C -- see L and L if you are using the Template Toolkit. Control directives like C, C, etc. must be highlighted in B. When seeing a green zone, the system will remove XML markup for the surrounding text and run nodes. If the directive is the only content of the paragraph, then the paragraph node is also removed. If this occurs within the first cell of a table row, the markup for that row is also removed. This mechanism ensures that the final result will not contain empty paragraphs or empty rows at places corresponding to control directives. In consequence of this distinction between yellow and green highlights, templating zones cannot mix data directives with control directives : a data directive within a green zone would generate output outside of the regular XML flow (paragraph nodes, run nodes and text nodes), and therefore MsWord would generate an error when trying to open such content. There is a workaround, however : data directives within a green zone will work if they I for paragraph nodes, run nodes and text nodes. To highlight using LibreOffice, set the Character Highlighting to Export As "Highlighting" instead of the default "Shading". See L. See also L for additional advice on authoring templates based on the L