Thank you for the amazing library! This has made my life much easier!
I am using your library to automatically fill out a packing slip. In order to make it easier to maintain and change, I am loading a Word Document as a Template, and then using setValue() to update variables. The template I am using has a lot of formatting and I would really prefer to avoid doing it in code if at all possible. It would also make it practically impossible for non-coders to update the template.
The issue I'm having is that I need to insert a multi-line replacement in several places (address, order notes, etc). Are there any plans to implement this in the future? Or am I missing another way to solve this problem, such as XSLT?
I could extend the Template Class with a setValueForPartMulti() and if I understand Word's Format correctly, my xml would need to look like the following:
<w:r>
<w:t>Hello</w:t>
<w:br/>
<w:t>world</wt>
</w:r>
Could I simply have my custom function preg_replace('\r\n', '<w:br/>', $value)? Would any issues arise from doing this?
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
You're welcome, @martindavis. I'm glad that PHPWord can helps you.
I haven't used template processor too much because, until now, I use PHPWord to create documents from scratch. I will start using it. In the meantime, I hope others can help answer your question.
Hi @ivanlanin I have solved it! In Template.php, line 340 add:
$replace = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $replace);
Interestingly enough, Word 2010 and Word 2003 do not have a problem if I just use '<w:br/>', but OpenOffice 3.4 does not recognize the newlines. If I use '</w:t><w:br/></wt>', Word 2010, Word 2003 and OpenOffice 3.4 recognize the newline character.
I think the decision from here is whether we use '~\R~u' or '~(*BSR_ANYCRLF)\R~'. The first is interpreted as (?>\r\n|\n|\r|\f|\x0b|\x85|\x{2028}|\x{2029}) while the second is interpreted as (?>\r\n|\n|\r). The first may be better because of line 338 where utf8_encode() is used. Adding ~u to the expression adds support for UTF-8 and ASCII. Source:
http://stackoverflow.com/questions/18988536/php-regex-how-to-match-r-and-n-without-using-r-n
Let me know which expression is better and I'll gladly fork to add the feature!
Thanks @martindavis. @RomanSyroeshko, perhaps you have some view about this? Thanks.
Hi, guys.
The problem is the similar to the one described here. Briefly, I can say the following.
Hardcoding XML tags in such way is a bad design. We need to let TemplateProcessor load documents as a bunch of objects (it deals with XML for now), but we have no volunteers who can suggest good implementation. I would like to implement this, but have no time because of job search. :(
Hi,
@ivanlanin is right.
ON Function : protected function setValueForPart($documentPartXML, $search, $replace, $limit)
AFTER : $replace = htmlspecialchars($replace);
$replace = preg_replace('~(*BSR_ANYCRLF)\R~', '< w : b r / >', $replace);
Will do the trick.
I have used @martindavis solution and it works like a charm. A real improvement over current situation in my opinion.
Both of these lines worked for me.
$replace = preg_replace('~\R~u', '/w:t
$replace = preg_replace('~(*BSR_ANYCRLF)\R~', '< w : b r / >', $replace);
However, I had to add into TemplateProcessor.php at line 352 because of a later version.
Thanks Andy
Not working for me!
Any suggestions?
protected function setValueForPart($documentPartXML, $search, $replace, $limit)
{
if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') {
$search = '${' . $search . '}';
}
if (!String::isUTF8($replace)) {
$replace = utf8_encode($replace);
}
//Lines added
$replace = preg_replace('~\R~u', '/w:t', $replace);
$replace = preg_replace('~(*BSR_ANYCRLF)\R~', '< w : b r / >', $replace);
// Note: we can't use the same function for both cases here, because of performance considerations.
if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) {
return str_replace($search, $replace, $documentPartXML);
} else {
$regExpDelim = '/';
$escapedSearch = preg_quote($search, $regExpDelim);
return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit);
}
}
And i'm using it: $document->setValue("hello", "hello \n world"));
@kuamatzin
Did you get it to work? Where did you put the code?
@maninderx No yet =(
@kuamatzin
this worked for me
`
//Lines added
$replace = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $replace);
`
@smandpartners-sipuni Thank you. This works.
//Lines added $replace = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $replace);
I also found that this line works in setValueForPart():
$replace = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $replace);
I put the line at the beginning of the function in v0.13.
Is there a reason that this hasn't been imported into the actual codebase?
@mhollander In version 0.13.0, the setValue('label',"value\nwith\nmultiline") works for me (linux PHP7 0.13.0 Libreoffice). Can you verify or explain to me what does not work?
@FBnil Thank you for looking into this and picking off some of the issues with this project.
I'm using 0.13.0 with PHP Version 7.0.22-0ubuntu0.16.04.1
I just reverted my version of PHPWord to not have my addtion and this still doesn't work. I am doing a setValue(setValue('label',"value\nwith\nmultiline") and I get "value\nwith\nmultiline" in the actual substitution. If I have literal newlines in my text string, I have the same problem.
@mhollander Ok, you are right, it is not PHPWord that add the w:br, it is LibreOffice that automatically fixes it after opening it. I'll do some tests if MSOffice doesn't mind the absence of revision id's (https://blogs.msdn.microsoft.com/brian_jones/2006/12/11/whats-up-with-all-those-rsids/).
I also checked shift-enter (a way to add multiline, in say, a bullet point list without going into a new bulletpoint, need to test all at the office. New testcase for the multiline are written and pass.
protected function setValueForPart($search, $replace, $documentPartXML, $limit)
{
// Shift-Enter
if (is_array($replace)) {
foreach ($replace as &$item) {
$item = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $item);
}
} else {
$replace = preg_replace('~\R~u', '</w:t><w:br/><w:t>', $replace);
}
// Note: we can't use the same function for both cases here, because of performance considerations.
if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) {
return str_replace($search, $replace, $documentPartXML);
} else {
$regExpEscaper = new RegExp();
return preg_replace($regExpEscaper->escape($search), $replace, $documentPartXML, $limit);
}
}
I use arrays a lot, say:
$a = [
'name' => 'Joe',
'age' => '42'
];
$templateProcessor->setValue(array_keys($a), array_values($a));
Addendum:
Do not confuse a newline inside a text, which converts to a new paragraph. You need to handle that with cloneBlock(), and then setValue() to the myline#n:
${myblock}
${myline}
${/myblock}
with a shift-Enter, which allows, for example:
* this
item
* another item
Even though visually, in most cases, they look the same.
Had exactly the same problem
Libreoffice: displays the files correctly probably by fixing the wrong code on the fly
Ms Office: everything is on a single line
Solutions provided here do the trick, see attached file for a simple extension class that applies the fix
It seems the solution of @marios88 was not implemented yet, but the error still exists. After adding the code from the Phptemplate_withnewline.php.txt it works like a charm for me.
Most helpful comment
Hi @ivanlanin I have solved it! In
Template.php,line 340add:Interestingly enough, Word 2010 and Word 2003 do not have a problem if I just use
'<w:br/>', but OpenOffice 3.4 does not recognize the newlines. If I use'</w:t><w:br/></wt>', Word 2010, Word 2003 and OpenOffice 3.4 recognize the newline character.I think the decision from here is whether we use
'~\R~u'or'~(*BSR_ANYCRLF)\R~'. The first is interpreted as(?>\r\n|\n|\r|\f|\x0b|\x85|\x{2028}|\x{2029})while the second is interpreted as(?>\r\n|\n|\r). The first may be better because ofline 338whereutf8_encode()is used. Adding~uto the expression adds support forUTF-8andASCII. Source:http://stackoverflow.com/questions/18988536/php-regex-how-to-match-r-and-n-without-using-r-n
Let me know which expression is better and I'll gladly fork to add the feature!