PHPWord
PHPWord copied to clipboard
If we load a docx using phpword then save it again, it should not be altered
I set up a docx document with a header and a footer, and some basics stylings for paragraph and headings ( as well a numbering rules or headings ) , the main idea was to open the document, and add some simple html in the first section so I can get a clean docx file ( with header, footer, and pagination and the correct styles ) . Sadly, I lost the header, footer, font setup for default styles, obviously IOFactory::load doesn't load all those aspects and we won't be able to save it back correctly as expected ( and I don't know if it can save it if it was correctly loaded ) . I would have been very nice to be able to keep those aspects so we can be able to create easily ready to use docx documents.
Any idea how we could fix this? Thank you
Originally posted by @rahal in https://github.com/PHPOffice/PHPWord/issues/882#issuecomment-461780347
Indeed, the IOFactory::load function unfortunately does not parse the whole docx specification. Your best option is to use the TemplateProcessor for this
Yes, thanks, that's exactly what I did
Hi @rahal,
How did you end up doing it with the template ? How do you make the html headings, etc use a set style in the docx ?
Thanks
@rahal bump ;)
Sorry.. I didn't saw the first notification. Well.. I prepare a docx template with all the styling, heading, footer, header, various setup as well as my "token" : content
``
use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings as WordSettings; use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWord\TemplateProcessor; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\Common\XMLWriter;
$templateProcessor = new TemplateProcessor($template); // let's get some xml content from our html $phpWord = new PhpWord('Word2007'); // Adding an empty Section to the document... $section = $phpWord->addSection(); Html::addHtml($section, $html, true, false); $writer = IOFactory::createWriter($phpWord, 'Word2007'); // convert the html to "word2017" xml $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY, './', WordSettings::hasCompatibility()); $containerWriter = new Container($xmlWriter, $section); $containerWriter->write(); $htmlAsXml = $xmlWriter->getData();
// remplace our templateContent WordSettings::setOutputEscapingEnabled(false); $templateProcessor->setValue('content', $htmlAsXml); WordSettings::setOutputEscapingEnabled(true);
// Save the file : $templateProcessor->saveAs($docxFilepath); ``
Something like that.. hope it helps By the way.. I works only with Microsoft Word ( the output didn't work correctly in libreoffice ) , if you have better luck, please let me know.
@rahal thanks for the example will try it out and let you know.
Hi @rahal ,
Your code works, I can finally add sections without breaking the templates !
Do you know if there is a way to apply custom styles that where set in the loaded template ex: MyStyle1. I see you can simply create H1, H2, H3 html tags for the different heading levels. I tried setting the class attribute to my html but that does not work.
<p class='MyStyle1'>Hello</p>
What about tables ? Have you had any luck inserting those ? Or do you simply add
<table><tr><td></td></tr></table>
?
Thanks a lot. Chris
Glad my code could help! You're welcome. For the styles, you can simply setup the default styles in the template, that's what I did. As for the tables, I didn't need them, did you try using them? If it doesn't work, I think It can be possible to add support for table elements.
On Fri, Jun 14, 2019, 20:04 ChrisRibe [email protected] wrote:
Hi @rahal https://github.com/rahal ,
Your code works, I can finally add sections without breaking the templates !
Do you know if there is a way to apply custom styles that where set in the loaded template ex: MyStyle1. I see you can simply create H1, H2, H3 html tags for the different heading levels. I tried setting the class attribute to my html but that does not work.
Hello
What about tables ? Have you had any luck inserting those ? Or do you simply add ?
Thanks a lot. Chris
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/PHPOffice/PHPWord/issues/1571?email_source=notifications&email_token=AAAINYZXV5RZM3BRPK26GDTP2PTVFA5CNFSM4GV5CNM2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXXWF4A#issuecomment-502227696, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAINY7PFNQJJSFCNNBQHBDP2PTVFANCNFSM4GV5CNMQ .
Well...
Seems you can use your trick to load just about anything into the template (tested title levels, tables, and text). Only thing for level styles you have to set them at least once in the template or else the styles do not stick.... odd. I also removed the Word2007 on the new PhpWord and it still works.
` use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table; use PhpOffice\PhpWord\TemplateProcessor; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\Common\XMLWriter;
//Solution to injet into templates without breaking things
function containerToXML($container){
$xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY, './', Settings::hasCompatibility());
$containerWriter = new Container($xmlWriter, $container);
$containerWriter->write();
return($xmlWriter->getData());
}
//1st working template load and inject content via xml...
$templateProcessor = new TemplateProcessor("e:/the-template.docx");
//Try and build xml from objects and insert xml instead...
$phpWord = new PhpWord();
$fontStyle = array();//if no style given levels do not register (if empty array defaults to template)
$phpWord->addTitleStyle(1, $fontStyle);
$phpWord->addTitleStyle(2, $fontStyle);
$phpWord->addTitleStyle(3, $fontStyle);
$section = $phpWord->addSection();
for($i=0;$i < 25;$i++){
$section->addText("Hello world $i");
}
//Table add test
$tbl = $section->addTable(array(
"layout" => Table::LAYOUT_AUTO,
"width" => 100 * 50, //in word 1% == 50 unit (with in 1/50)
"unit" => TblWidth::PERCENT
));
$tbl->addRow(900, array('tblHeader' => true));
$tbl->addCell(150)->addText('Header1');
$tbl->addCell(150)->addText('Header2');
$tbl->addCell(150)->addText('Header3');
$tbl->addCell(150)->addText('Header4');
for($i=0;$i < 40;$i++){
$tbl->addRow();
$tbl->addCell(150)->addText("cell 1 row:$i");
$tbl->addCell(150)->addText("cell 2 row:$i");
$tbl->addCell(150)->addText("cell 3 row:$i");
$tbl->addCell(150)->addText("cell 4 row:$i");
}
$section->addTitle('Level 1', 1);
$section->addTitle('Level 2', 2);
$section->addTitle('Level 3', 3);
$elXml = containerToXML($section);
// remplace our templateContent
Settings::setOutputEscapingEnabled(false);
$templateProcessor->setValue('content', $elXml);
Settings::setOutputEscapingEnabled(true);
// Save the file :
$templateProcessor->saveAs("e:/demo-xml-inject.docx");
`
@troosan could this be added to php word template processor so templates are more flexible ?
Thanks again @rahal
You are welcome @chrisribe