From fb863cdf21df3fc82ef266696354cfad692fbb0e Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 30 Jul 2016 16:02:23 +0400 Subject: [PATCH] https://github.com/PHPOffice/PHPWord/issues/335. --- CHANGELOG.md | 1 + README.md | 2 +- composer.json | 2 +- docs/intro.rst | 3 +- docs/templates-processing.rst | 2 +- src/PhpWord/TemplateProcessor.php | 113 ++++++++++++------ tests/PhpWord/TemplateProcessorTest.php | 46 ++++--- .../documents/without_table_macros.docx | Bin 5083 -> 6304 bytes .../_files/templates/with_table_macros.docx | Bin 5375 -> 7379 bytes 9 files changed, 110 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f9745d7..145b6a31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Place announcement text here. - Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko - Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618 - Introduced automatic output escaping for OOXML, ODF, HTML, and RTF. To turn the feature on use `phpword.ini` or `\PhpOffice\PhpWord\Settings`. - @RomanSyroeshko #483 +- Supported processing of headers and footers in `TemplateProcessor::applyXslStyleSheet()`. - @RomanSyroeshko #335 ### Changed - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 diff --git a/README.md b/README.md index 3c2bd5c1..949238a7 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ With PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your - Insert charts (pie, doughnut, bar, line, area, scatter, radar) - Insert form fields (textinput, checkbox, and dropdown) - Create document from templates -- Use XSL 1.0 style sheets to transform main document part of OOXML template +- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template - ... and many more features on progress ## Requirements diff --git a/composer.json b/composer.json index e9399914..c49eb9cd 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", "ext-xmlwriter": "Allows writing OOXML and ODF", - "ext-xsl": "Allows applying XSL style sheet to main document part of OOXML template", + "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template", "dompdf/dompdf": "Allows writing PDF" }, "autoload": { diff --git a/docs/intro.rst b/docs/intro.rst index 0ef27c9f..d1c791cf 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -50,8 +50,7 @@ Features - Insert charts (pie, doughnut, bar, line, area, scatter, radar) - Insert form fields (textinput, checkbox, and dropdown) - Create document from templates -- Use XSL 1.0 style sheets to transform main document part of OOXML - template +- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template - ... and many more features on progress File formats diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 1c0b8b03..af03b245 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -15,7 +15,7 @@ Example: $templateProcessor->setValue('Name', 'John Doe'); $templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street')); -It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform main document part of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). +It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform headers, main document part, and footers of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). See ``Sample_07_TemplateCloneRow.php`` for example on how to create multirow from a single row in a template by using ``TemplateProcessor::cloneRow``. diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5f131901..d2a306e9 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -100,7 +100,49 @@ class TemplateProcessor ); $index++; } - $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); + $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName($this->getMainPartName())); + } + + /** + * @param string $xml + * @param \XSLTProcessor $xsltProcessor + * + * @return string + * + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + protected function transformSingleXml($xml, $xsltProcessor) + { + $domDocument = new \DOMDocument(); + if (false === $domDocument->loadXML($xml)) { + throw new Exception('Could not load the given XML document.'); + } + + $transformedXml = $xsltProcessor->transformToXml($domDocument); + if (false === $transformedXml) { + throw new Exception('Could not transform the given XML document.'); + } + + return $transformedXml; + } + + /** + * @param mixed $xml + * @param \XSLTProcessor $xsltProcessor + * + * @return mixed + */ + protected function transformXml($xml, $xsltProcessor) + { + if (is_array($xml)) { + foreach ($xml as &$item) { + $item = $this->transformSingleXml($item, $xsltProcessor); + } + } else { + $xml = $this->transformSingleXml($xml, $xsltProcessor); + } + + return $xml; } /** @@ -109,35 +151,26 @@ class TemplateProcessor * Note: since the method doesn't make any guess on logic of the provided XSL style sheet, * make sure that output is correctly escaped. Otherwise you may get broken document. * - * @param \DOMDocument $xslDOMDocument + * @param \DOMDocument $xslDomDocument * @param array $xslOptions - * @param string $xslOptionsURI + * @param string $xslOptionsUri * * @return void * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') + public function applyXslStyleSheet($xslDomDocument, $xslOptions = array(), $xslOptionsUri = '') { $xsltProcessor = new \XSLTProcessor(); - $xsltProcessor->importStylesheet($xslDOMDocument); - - if (false === $xsltProcessor->setParameter($xslOptionsURI, $xslOptions)) { + $xsltProcessor->importStylesheet($xslDomDocument); + if (false === $xsltProcessor->setParameter($xslOptionsUri, $xslOptions)) { throw new Exception('Could not set values for the given XSL style sheet parameters.'); } - $xmlDOMDocument = new \DOMDocument(); - if (false === $xmlDOMDocument->loadXML($this->tempDocumentMainPart)) { - throw new Exception('Could not load XML from the given template.'); - } - - $xmlTransformed = $xsltProcessor->transformToXml($xmlDOMDocument); - if (false === $xmlTransformed) { - throw new Exception('Could not transform the given XML document.'); - } - - $this->tempDocumentMainPart = $xmlTransformed; + $this->tempDocumentHeaders = $this->transformXml($this->tempDocumentHeaders, $xsltProcessor); + $this->tempDocumentMainPart = $this->transformXml($this->tempDocumentMainPart, $xsltProcessor); + $this->tempDocumentFooters = $this->transformXml($this->tempDocumentFooters, $xsltProcessor); } /** @@ -365,14 +398,14 @@ class TemplateProcessor */ public function save() { - foreach ($this->tempDocumentHeaders as $index => $headerXML) { - $this->zipClass->addFromString($this->getHeaderName($index), $this->tempDocumentHeaders[$index]); + foreach ($this->tempDocumentHeaders as $index => $xml) { + $this->zipClass->addFromString($this->getHeaderName($index), $xml); } - $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart); + $this->zipClass->addFromString($this->getMainPartName(), $this->tempDocumentMainPart); - foreach ($this->tempDocumentFooters as $index => $headerXML) { - $this->zipClass->addFromString($this->getFooterName($index), $this->tempDocumentFooters[$index]); + foreach ($this->tempDocumentFooters as $index => $xml) { + $this->zipClass->addFromString($this->getFooterName($index), $xml); } // Close zip file @@ -414,8 +447,6 @@ class TemplateProcessor * Finds parts of broken macros and sticks them together. * Macros, while being edited, could be implicitly broken by some of the word processors. * - * @since 0.13.0 - * * @param string $documentPart The document part in XML representation. * * @return string @@ -470,18 +501,6 @@ class TemplateProcessor return $matches[1]; } - /** - * Get the name of the footer file for $index. - * - * @param integer $index - * - * @return string - */ - protected function getFooterName($index) - { - return sprintf('word/footer%d.xml', $index); - } - /** * Get the name of the header file for $index. * @@ -494,6 +513,26 @@ class TemplateProcessor return sprintf('word/header%d.xml', $index); } + /** + * @return string + */ + protected function getMainPartName() + { + return 'word/document.xml'; + } + + /** + * Get the name of the footer file for $index. + * + * @param integer $index + * + * @return string + */ + protected function getFooterName($index) + { + return sprintf('word/footer%d.xml', $index); + } + /** * Find the start position of the nearest table row before $offset. * diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index c5a4b1a3..3c2b8e46 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -35,10 +35,10 @@ final class TemplateProcessorTest extends \PHPUnit_Framework_TestCase $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx'; $templateProcessor = new TemplateProcessor($templateFqfn); - $xslDOMDocument = new \DOMDocument(); - $xslDOMDocument->load(__DIR__ . "/_files/xsl/remove_tables_by_needle.xsl"); - foreach (array('${employee.', '${scoreboard.') as $needle) { - $templateProcessor->applyXslStyleSheet($xslDOMDocument, array('needle' => $needle)); + $xslDomDocument = new \DOMDocument(); + $xslDomDocument->load(__DIR__ . "/_files/xsl/remove_tables_by_needle.xsl"); + foreach (array('${employee.', '${scoreboard.', '${reference.') as $needle) { + $templateProcessor->applyXslStyleSheet($xslDomDocument, array('needle' => $needle)); } $documentFqfn = $templateProcessor->save(); @@ -48,19 +48,25 @@ final class TemplateProcessorTest extends \PHPUnit_Framework_TestCase $templateZip = new \ZipArchive(); $templateZip->open($templateFqfn); - $templateXml = $templateZip->getFromName('word/document.xml'); + $templateHeaderXml = $templateZip->getFromName('word/header1.xml'); + $templateMainPartXml = $templateZip->getFromName('word/document.xml'); + $templateFooterXml = $templateZip->getFromName('word/footer1.xml'); if (false === $templateZip->close()) { throw new \Exception("Could not close zip file \"{$templateZip}\"."); } $documentZip = new \ZipArchive(); $documentZip->open($documentFqfn); - $documentXml = $documentZip->getFromName('word/document.xml'); + $documentHeaderXml = $documentZip->getFromName('word/header1.xml'); + $documentMainPartXml = $documentZip->getFromName('word/document.xml'); + $documentFooterXml = $documentZip->getFromName('word/footer1.xml'); if (false === $documentZip->close()) { throw new \Exception("Could not close zip file \"{$documentZip}\"."); } - $this->assertNotEquals($documentXml, $templateXml); + $this->assertNotEquals($templateHeaderXml, $documentHeaderXml); + $this->assertNotEquals($templateMainPartXml, $documentMainPartXml); + $this->assertNotEquals($templateFooterXml, $documentFooterXml); return $documentFqfn; } @@ -82,19 +88,25 @@ final class TemplateProcessorTest extends \PHPUnit_Framework_TestCase $actualDocumentZip = new \ZipArchive(); $actualDocumentZip->open($actualDocumentFqfn); - $actualDocumentXml = $actualDocumentZip->getFromName('word/document.xml'); + $actualHeaderXml = $actualDocumentZip->getFromName('word/header1.xml'); + $actualMainPartXml = $actualDocumentZip->getFromName('word/document.xml'); + $actualFooterXml = $actualDocumentZip->getFromName('word/footer1.xml'); if (false === $actualDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$actualDocumentFqfn}\"."); } $expectedDocumentZip = new \ZipArchive(); $expectedDocumentZip->open($expectedDocumentFqfn); - $expectedDocumentXml = $expectedDocumentZip->getFromName('word/document.xml'); + $expectedHeaderXml = $expectedDocumentZip->getFromName('word/header1.xml'); + $expectedMainPartXml = $expectedDocumentZip->getFromName('word/document.xml'); + $expectedFooterXml = $expectedDocumentZip->getFromName('word/footer1.xml'); if (false === $expectedDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$expectedDocumentFqfn}\"."); } - $this->assertXmlStringEqualsXmlString($expectedDocumentXml, $actualDocumentXml); + $this->assertXmlStringEqualsXmlString($expectedHeaderXml, $actualHeaderXml); + $this->assertXmlStringEqualsXmlString($expectedMainPartXml, $actualMainPartXml); + $this->assertXmlStringEqualsXmlString($expectedFooterXml, $actualFooterXml); } /** @@ -109,14 +121,14 @@ final class TemplateProcessorTest extends \PHPUnit_Framework_TestCase { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); - $xslDOMDocument = new \DOMDocument(); - $xslDOMDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); + $xslDomDocument = new \DOMDocument(); + $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); /* * We have to use error control below, because \XSLTProcessor::setParameter omits warning on failure. * This warning fails the test. */ - @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => 'somevalue')); + @$templateProcessor->applyXslStyleSheet($xslDomDocument, array(1 => 'somevalue')); } /** @@ -124,21 +136,21 @@ final class TemplateProcessorTest extends \PHPUnit_Framework_TestCase * * @covers ::applyXslStyleSheet * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage Could not load XML from the given template. + * @expectedExceptionMessage Could not load the given XML document. * @test */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplate() { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx'); - $xslDOMDocument = new \DOMDocument(); - $xslDOMDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); + $xslDomDocument = new \DOMDocument(); + $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); /* * We have to use error control below, because \DOMDocument::loadXML omits warning on failure. * This warning fails the test. */ - @$templateProcessor->applyXslStyleSheet($xslDOMDocument); + @$templateProcessor->applyXslStyleSheet($xslDomDocument); } /** diff --git a/tests/PhpWord/_files/documents/without_table_macros.docx b/tests/PhpWord/_files/documents/without_table_macros.docx index e4e9767fc1aa165ae5b86947c9af49950cb5b787..316a1df762202dd257b8c11ad7ea1166dd8a93a5 100644 GIT binary patch literal 6304 zcmaJ_1yq##w;j5BC;>_71_cq2PKhC;yJP5W%k$ z|9W}v|7O;jZ_TXPzi)l}oU_k4TU{9i6$k)eVgj)BuNA(IA~Ajj003gh000i+YT{<) z=+49a^Ann?qKqPm8@YEyD!sel$PwKKJ7JJ=W;n(O&)VJ{g<%NTL2ni%vEQr5=Jz)H z9_~|*gJIYCsyT6SlAW*YBwcyO-t*e~%!%>PnojV%*AY*iRLU}Bf3+B1Xhy7<6y5z~ zyF!r9wLF{NT1}%@)SRKVEX8%9;WRUdKR=IeYTCZf-~)2~g~FxK13$7Frf_C!<5I)7 zwZhz_s=k(ErbWILuIKiG5L_Q4+pA{e^ouIS- zU~{kInDI*7aAD_Xs-ryhe=!hZ;XUAh1OUt-7$8D0VCih3?&j>`&ST;1X2tCTb_~!k zQVZh+2At|7w@Tx@OCmIlc_G%+#TwVssK2XAsx;wcadApU;rMN3PV6-2<;9ebYq^pQ zfzqKqQ{O43n?#k!Mxnx}h{1dJFSgRMs)PCxp^5op3@tHP@w!mB;uLZEaz2d%lSh|j zXhTmQrp0iBI%r2PqUuZOQ_}lnuaK1oT5XYp=`3S8cm>NMSEffHMT{bP>yCBlkF>qe zA9kusp>^19KNA;sz$;fW2^i%gABfE^3V%HwLOq2sEN?a;XiVazG1r!~^fZZQp`4q1 z=M_c1p!j`aKD0@RUEQ#99wFYh%U9A3GIkP|2G3EQcn2@-fRSV2&An$c7t>Wq4v>az z%1^==!@%b~i&ZQ^Oq|>mtX^Kr6|+qvTdMq}vzi%N*$}ZGk+O=c2|+peDph;!USY*mOyG>vtJcJ&xiW21d6>YxPvxYO z2b6}*V5hIIr_kR#hZn;04QU7#v+<-733&OQqw1lROn8}#tIshmc&2t1t(%arCe;Yu z!&JSS4yfj@HS_nJr@jhOiCBLgxLYKa4WAh$V;0~iz>^KCntGW4&B<>U9Rcz12VOd=xSMkJj@p$#eD-| zbkxES&Azf@s37Euimrvb4prxta&85;2mxM+=G0l|XCLFLT!O#<=GkC7tuS;r#=-GgA> zWGrGg$21qR8wN#aOdwp`dVZ_d4oEXA-(ADq8x-5B(}1e}6Z#_^Nhip67@n=nzeazy z$!GzJQn51RVN=j?=a@2@?rU`Qhdb>eeNJN;R7T?FAu;VXJ)m*c)P{EO6b1TC9wE1j z;nDnnvl=BZnNEWCk*@Ew8IdgIbB>Aa7pZ2PeYk%P;S=0Q@=LjC;x^Hwccy_cJ}D|8 zywH9WEK@LeNcJR+t%G?@Z4Gvf^zRg$z_|c(B3Mbl1po;CVaDCV*U`%TCnGJ|YHD-5 zz_vY2nbzlZZzObx2)DFCP#0vDtBSIPp-~n#4bnQQ6Zjt-PjedsLUswLLhbVCujHPo zre&mhaj~njsa#S&Zd;;lb98FM%Jft!E)0ECUZ){Lwp_W->ip>IS-EjJowD7K*bpiU z{x_nChQ_;Kuh&Ya6dCaO!zJiNNnm$9D&wH zZmwdG4q8x-m3#_+dOB;UFmE1A_D#|tc#33KU}ZJh&MNYI#FMB^)}|@6nSpOltKHZ< zN5#QJSes~#FJv@m+qG<>UQ=qKa6BOhF)5Y@rseu2KC|qaFczI zqbfraUa{{tP2?i@{45>9mk{sfMv=uFy^L8PXpRldci>cWF?`u`;FdYC zhXl<2_M}*N5b`dCqdHQ0HLa;wjn8ws@g!th4j8;Pi5o;EztpiLw4)GpbHCojL@%*K zsa4EBfu}(7GVvnJ`@q-#{+W+=xLEvmweOkY(%Bc3c?63+Z7XqS1o1Gg;F+X0N%Cfj zW?KJuLdnWzNEbuSOL27lnN864URvYlE>%ZbLXDA+rYCF0p&8#@+TyFbuWn4|GDCJ$ z*K~)c8kMVrimd_}+a@&bZYWjY6zsi8-&O=)-IAPn#sd{9gtluVii`N4!m@UD^3XCf zcl@jE)~o-c?iqWN1sLIlrKH3w;ePpRC=Yf^t1aI$zE$j7T3x57??WnZtM#_Fv9_tb zaCurs@yUn%%L02Evf@Qrfjj+D;z%Qbh6}1l$Z>eYcFLO5v)aw?1Dcj8(=msY$)52l zmB6h#H2VWW3RtiGT?i+HaWbIQ?nrO?drp@f(vn4Vh zadmkh&6Juo<&MX2v$(JwjR{*;_o_DgVF(g>;DsD?*tL`K4;J4!`A9i8GQm5Fk
  • 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 literal 5083 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%0D)~<8jdjMHB9PJftS^?L_-xag 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 T8RhOF%-gH+HbRie?(Y5v_n4sB delta 4642 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