senny / sablon

Ruby Document Template Processor based on docx templates and Mail Merge fields.
MIT License
446 stars 128 forks source link

Search a template for a specific merge field? #114

Closed cchandler81 closed 5 years ago

cchandler81 commented 6 years ago

Is it possible to search a template for a specific merge field? I'd like to run unique logic if a given merge field exists on a template. For example, if the template includes a merge field for "person" and I have 2 such objects in my db, I could then generate two docs, one for each person. Hopefully that makes sense... Thanks!

stadelmanma commented 6 years ago

Hi @cchandler81, the MailMerge parser could probably be used on it's own, separate from a template to do what you want. Below is some roughed out (untested) code that might get you going in the right direction.

# Load in the content however you want, the entry name you'll need to
# fetch from the zip archive is "word/document.xml"
# Some of the code in
# https://github.com/senny/sablon/blob/master/lib/sablon/document_object_model/model.rb
# might be useful in that regard
xml_node = Nokogiri::XML(content)

# returns array of SimpleField and ComplexField instances
# See: https://github.com/senny/sablon/blob/master/lib/sablon/parser/mail_merge.rb#L132
# for some additional implementation details
parser = Sablon::Parser::MailMerge.new
fields = parser.parse_fields(xml_node))

# returns True if a field's expression matches "person"
one_doc_per_person = fields.any? do |fld|
  fld.expression =~ /person/
end
cchandler81 commented 6 years ago

That is definitely a good starting point, much obliged.

stadelmanma commented 6 years ago

Glad to help, would you mind sharing a few more details on your use case?

I could see this being a useful feature for working with a "packet" of documents (read: templates) where maybe only the cover letter needs fully regenerated for each record. The rest of the files are simply cached and copied for each "person" instead of being re-parsed which is a performance intensive task for large templates.

cchandler81 commented 6 years ago

I have "letters" that may need to be generated for multiple recipients based on the type of recipient used in the MergeField. If a certain recipient type exists in the doc then my app will know there are multiple and to loop through each. Most of my cases are one or two pagers but I will probably have cases where only the cover page needs to be regenerated since the remaining content is the same across all recipients (e.g. a status update on work being performed the is relevant to all recipients).