PhpWord 输出在 LibreOffice 中不起作用,但在 MS Word 中工作正常
PhpWord output doesn't work in LibreOffice but works fine in MS Word
这与 GitHub 页面 [link] 上列出的一个半已知问题有关,其中 PhpWord 生成表格的方式导致它将单元格宽度设置为“”,这不是在 LibreOffice 中有效,但在 Word 中没问题。
GitHub 上的问题具体列出了 html 到单词的转换,但我在使用常规的面向对象接口时也遇到了这个问题。
我试过手动设置单元格宽度,但似乎没有任何效果。
我想问问是否有人对此问题有任何解决方法,因为它几乎不可能在无法访问 MS Word 的情况下在 Linux 框中调试我的输出。我需要为客户导出 .docx。
为什么不直接导出到 .odt 来测试呢?如果我这样做,它也不会呈现我在页面上的列表.....
这是我正在使用的文档的粗略大纲(由于保密协议,我不能随意分享确切的代码):
$document = new PhpWord\PhpWord();
$section = $document->addSection();
// This list doesn't get rendered in the ODT file
$section->addListItem('Employee ID: 98765');
$section->addListItem('First Name: John');
$section->addListItem('Last Name: Doe');
$section->addListItem('SSN: 12345');
// This table has errors in LibreOffice when exported to .docx
if ($show_adv_details) {
$table = $section->addTable();
$table->addRow();
$table->addCell()->addText('SSN');
$table->addCell()->addText('Email');
$table->addCell()->addText('Phone No');
$table->addRow();
$table->addCell()->addText('12345');
$table->addCell()->addText('jd@example.com');
$table->addCell()->addText('999 1234');
// repeat ad nauseam
}
$section->addTitle('Comment');
$section->addTitle('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.');
我在 Ubuntu.
上使用 PHP 7.0(古老的遗留系统,对此无能为力)
最后在这里重申一下这个问题:
我可以做些什么来使该文档在所有不同的输出上正确呈现吗?该文档似乎没有太大帮助。
好吧,我不是 PHPOffice 包的维护者,但这是我在包代码中挖掘并解决你的两个问题的解决方法:
- ODT 列表不起作用;
- 使用 LibreOffice 打开时 Word2007 Writer 上的表格不起作用。
我意识到 ListItem.php class 在 ODText writer 上不存在,我想这就是为什么你不能将列表添加到 . odt 文件。
您需要手动将宽度添加到列中以使其在 LibreOffice 上工作(如 Nigel 所说,您可以通过每个 addCell()
调用并添加一些数字,即使是“1”也可以).
如何解决这两个问题
我们将使用一些修复问题的更新“覆盖”原始文件。
为了让它工作,你应该使用 Composer 安装 PHPWord。
(这是安装指南中唯一可用的选项,但还有其他方法)。
没有 Composer,在 PHPWord require 之后 require 自定义文件(我认为它有效)。或者直接更改文件所在位置(一个坏主意)。
文件
创建这样的结构:
Custom
├── Element
│ └── Table.php
└── Writer
└── ODText
└── Element
└── ListItem.php
当然,你可以使用任何其他的,但我们要“覆盖”原始包文件,所以我保留了它的结构。
我们将使用 Autoload Files 获取这些文件:
composer.json:
...
"autoload": {
"files": [
"Custom/Element/Table.php",
"Custom/Writer/ODText/Element/ListItem.php"
]
},
...
如果您的 composer.json 上没有“自动加载”键,您必须添加它,“文件”键也是如此。
运行 composer dump-autoload
更新更改。
自定义 classes
现在,我们必须将代码添加到自定义文件中。
Custom/Writer/ODText/Element/ListItem.php:
<?php
namespace PhpOffice\PhpWord\Writer\ODText\Element;
/**
* ListItem element writer
*/
class ListItem extends AbstractElement
{
/**
* Write list item element.
*/
public function write()
{
$xmlWriter = $this->getXmlWriter();
$element = $this->getElement();
if (!$element instanceof \PhpOffice\PhpWord\Element\ListItem) {
return;
}
$textObject = $element->getTextObject();
$xmlWriter->startElement('text:list');
$xmlWriter->writeAttribute('text:style-name', 'L1');
$xmlWriter->startElement('text:list-item');
$xmlWriter->startElement('text:p');
$xmlWriter->writeAttribute('text:style-name', 'P1');
$elementWriter = new Text($xmlWriter, $textObject, true);
$elementWriter->write();
$xmlWriter->endElement(); // text:list
$xmlWriter->endElement(); // text:p
$xmlWriter->endElement(); // text:list-item
}
}
文件由Word2007版本改编而来,解决了您的第一个问题。现在列表将适用于 ODText。
Custom/Element/Table.php:
<?php
namespace PhpOffice\PhpWord\Element;
use PhpOffice\PhpWord\Style\Table as TableStyle;
/**
* Table element writer
*/
class Table extends AbstractElement
{
/**
* Table style
*
* @var \PhpOffice\PhpWord\Style\Table
*/
private $style;
/**
* Table rows
*
* @var \PhpOffice\PhpWord\Element\Row[]
*/
private $rows = array();
/**
* Table width
*
* @var int
*/
private $width = null;
/**
* Create a new table
*
* @param mixed $style
*/
public function __construct($style = null)
{
$this->style = $this->setNewStyle(new TableStyle(), $style);
}
/**
* Add a row
*
* @param int $height
* @param mixed $style
* @return \PhpOffice\PhpWord\Element\Row
*/
public function addRow($height = null, $style = null)
{
$row = new Row($height, $style);
$row->setParentContainer($this);
$this->rows[] = $row;
return $row;
}
/**
* Add a cell
*
* @param int $width
* @param mixed $style
* @return \PhpOffice\PhpWord\Element\Cell
*/
public function addCell($width = 1, $style = null)
{
$index = count($this->rows) - 1;
$row = $this->rows[$index];
$cell = $row->addCell($width, $style);
return $cell;
}
/**
* Get all rows
*
* @return \PhpOffice\PhpWord\Element\Row[]
*/
public function getRows()
{
return $this->rows;
}
/**
* Get table style
*
* @return \PhpOffice\PhpWord\Style\Table
*/
public function getStyle()
{
return $this->style;
}
/**
* Get table width
*
* @return int
*/
public function getWidth()
{
return $this->width;
}
/**
* Set table width.
*
* @param int $width
*/
public function setWidth($width)
{
$this->width = $width;
}
/**
* Get column count
*
* @return int
*/
public function countColumns()
{
$columnCount = 0;
$rowCount = count($this->rows);
for ($i = 0; $i < $rowCount; $i++) {
/** @var \PhpOffice\PhpWord\Element\Row $row Type hint */
$row = $this->rows[$i];
$cellCount = count($row->getCells());
if ($columnCount < $cellCount) {
$columnCount = $cellCount;
}
}
return $columnCount;
}
/**
* The first declared cell width for each column
*
* @return int[]
*/
public function findFirstDefinedCellWidths()
{
$cellWidths = array();
foreach ($this->rows as $row) {
$cells = $row->getCells();
if (count($cells) <= count($cellWidths)) {
continue;
}
$cellWidths = array();
foreach ($cells as $cell) {
$cellWidths[] = $cell->getWidth();
}
}
return $cellWidths;
}
}
因为我们正在“覆盖”文件,所以我们不能重复使用扩展它的原始文件(至少,我不知道如何)。此处唯一的变化是 public function addCell($width = 1, $style = null)
始终将“1”作为函数的默认值。这解决了您的第二个问题,现在您可以在没有值的情况下调用 $table->addCell()
。
演示
require __DIR__ . '/vendor/autoload.php';
$document = new \PhpOffice\PhpWord\PhpWord();
$section = $document->addSection();
// This list **does** get rendered in the ODT file
$section->addListItem('Employee ID: 98765');
$section->addListItem('First Name: John');
$section->addListItem('Last Name: Doe');
$section->addListItem('SSN: 12345');
$table = $section->addTable();
$table->addRow();
$table->addCell()->addText('SSN');
$table->addCell()->addText('Email');
$table->addCell()->addText('Phone No');
$table->addRow();
$table->addCell()->addText('12345');
$table->addCell()->addText('jd@example.com');
$table->addCell()->addText('999 1234');
// Save the document as DOCX
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($document, 'Word2007');
$objWriter->save('document.docx');
// Save the document as ODT
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($document, 'ODText');
$objWriter->save('document.odt');
这与 GitHub 页面 [link] 上列出的一个半已知问题有关,其中 PhpWord 生成表格的方式导致它将单元格宽度设置为“”,这不是在 LibreOffice 中有效,但在 Word 中没问题。
GitHub 上的问题具体列出了 html 到单词的转换,但我在使用常规的面向对象接口时也遇到了这个问题。
我试过手动设置单元格宽度,但似乎没有任何效果。
我想问问是否有人对此问题有任何解决方法,因为它几乎不可能在无法访问 MS Word 的情况下在 Linux 框中调试我的输出。我需要为客户导出 .docx。
为什么不直接导出到 .odt 来测试呢?如果我这样做,它也不会呈现我在页面上的列表.....
这是我正在使用的文档的粗略大纲(由于保密协议,我不能随意分享确切的代码):
$document = new PhpWord\PhpWord();
$section = $document->addSection();
// This list doesn't get rendered in the ODT file
$section->addListItem('Employee ID: 98765');
$section->addListItem('First Name: John');
$section->addListItem('Last Name: Doe');
$section->addListItem('SSN: 12345');
// This table has errors in LibreOffice when exported to .docx
if ($show_adv_details) {
$table = $section->addTable();
$table->addRow();
$table->addCell()->addText('SSN');
$table->addCell()->addText('Email');
$table->addCell()->addText('Phone No');
$table->addRow();
$table->addCell()->addText('12345');
$table->addCell()->addText('jd@example.com');
$table->addCell()->addText('999 1234');
// repeat ad nauseam
}
$section->addTitle('Comment');
$section->addTitle('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.');
我在 Ubuntu.
上使用 PHP 7.0(古老的遗留系统,对此无能为力)最后在这里重申一下这个问题:
我可以做些什么来使该文档在所有不同的输出上正确呈现吗?该文档似乎没有太大帮助。
好吧,我不是 PHPOffice 包的维护者,但这是我在包代码中挖掘并解决你的两个问题的解决方法:
- ODT 列表不起作用;
- 使用 LibreOffice 打开时 Word2007 Writer 上的表格不起作用。
我意识到 ListItem.php class 在 ODText writer 上不存在,我想这就是为什么你不能将列表添加到 . odt 文件。
您需要手动将宽度添加到列中以使其在 LibreOffice 上工作(如 Nigel 所说,您可以通过每个 addCell()
调用并添加一些数字,即使是“1”也可以).
如何解决这两个问题
我们将使用一些修复问题的更新“覆盖”原始文件。 为了让它工作,你应该使用 Composer 安装 PHPWord。 (这是安装指南中唯一可用的选项,但还有其他方法)。
没有 Composer,在 PHPWord require 之后 require 自定义文件(我认为它有效)。或者直接更改文件所在位置(一个坏主意)。
文件
创建这样的结构:
Custom
├── Element
│ └── Table.php
└── Writer
└── ODText
└── Element
└── ListItem.php
当然,你可以使用任何其他的,但我们要“覆盖”原始包文件,所以我保留了它的结构。
我们将使用 Autoload Files 获取这些文件:
composer.json:
...
"autoload": {
"files": [
"Custom/Element/Table.php",
"Custom/Writer/ODText/Element/ListItem.php"
]
},
...
如果您的 composer.json 上没有“自动加载”键,您必须添加它,“文件”键也是如此。
运行 composer dump-autoload
更新更改。
自定义 classes
现在,我们必须将代码添加到自定义文件中。
Custom/Writer/ODText/Element/ListItem.php:
<?php
namespace PhpOffice\PhpWord\Writer\ODText\Element;
/**
* ListItem element writer
*/
class ListItem extends AbstractElement
{
/**
* Write list item element.
*/
public function write()
{
$xmlWriter = $this->getXmlWriter();
$element = $this->getElement();
if (!$element instanceof \PhpOffice\PhpWord\Element\ListItem) {
return;
}
$textObject = $element->getTextObject();
$xmlWriter->startElement('text:list');
$xmlWriter->writeAttribute('text:style-name', 'L1');
$xmlWriter->startElement('text:list-item');
$xmlWriter->startElement('text:p');
$xmlWriter->writeAttribute('text:style-name', 'P1');
$elementWriter = new Text($xmlWriter, $textObject, true);
$elementWriter->write();
$xmlWriter->endElement(); // text:list
$xmlWriter->endElement(); // text:p
$xmlWriter->endElement(); // text:list-item
}
}
文件由Word2007版本改编而来,解决了您的第一个问题。现在列表将适用于 ODText。
Custom/Element/Table.php:
<?php
namespace PhpOffice\PhpWord\Element;
use PhpOffice\PhpWord\Style\Table as TableStyle;
/**
* Table element writer
*/
class Table extends AbstractElement
{
/**
* Table style
*
* @var \PhpOffice\PhpWord\Style\Table
*/
private $style;
/**
* Table rows
*
* @var \PhpOffice\PhpWord\Element\Row[]
*/
private $rows = array();
/**
* Table width
*
* @var int
*/
private $width = null;
/**
* Create a new table
*
* @param mixed $style
*/
public function __construct($style = null)
{
$this->style = $this->setNewStyle(new TableStyle(), $style);
}
/**
* Add a row
*
* @param int $height
* @param mixed $style
* @return \PhpOffice\PhpWord\Element\Row
*/
public function addRow($height = null, $style = null)
{
$row = new Row($height, $style);
$row->setParentContainer($this);
$this->rows[] = $row;
return $row;
}
/**
* Add a cell
*
* @param int $width
* @param mixed $style
* @return \PhpOffice\PhpWord\Element\Cell
*/
public function addCell($width = 1, $style = null)
{
$index = count($this->rows) - 1;
$row = $this->rows[$index];
$cell = $row->addCell($width, $style);
return $cell;
}
/**
* Get all rows
*
* @return \PhpOffice\PhpWord\Element\Row[]
*/
public function getRows()
{
return $this->rows;
}
/**
* Get table style
*
* @return \PhpOffice\PhpWord\Style\Table
*/
public function getStyle()
{
return $this->style;
}
/**
* Get table width
*
* @return int
*/
public function getWidth()
{
return $this->width;
}
/**
* Set table width.
*
* @param int $width
*/
public function setWidth($width)
{
$this->width = $width;
}
/**
* Get column count
*
* @return int
*/
public function countColumns()
{
$columnCount = 0;
$rowCount = count($this->rows);
for ($i = 0; $i < $rowCount; $i++) {
/** @var \PhpOffice\PhpWord\Element\Row $row Type hint */
$row = $this->rows[$i];
$cellCount = count($row->getCells());
if ($columnCount < $cellCount) {
$columnCount = $cellCount;
}
}
return $columnCount;
}
/**
* The first declared cell width for each column
*
* @return int[]
*/
public function findFirstDefinedCellWidths()
{
$cellWidths = array();
foreach ($this->rows as $row) {
$cells = $row->getCells();
if (count($cells) <= count($cellWidths)) {
continue;
}
$cellWidths = array();
foreach ($cells as $cell) {
$cellWidths[] = $cell->getWidth();
}
}
return $cellWidths;
}
}
因为我们正在“覆盖”文件,所以我们不能重复使用扩展它的原始文件(至少,我不知道如何)。此处唯一的变化是 public function addCell($width = 1, $style = null)
始终将“1”作为函数的默认值。这解决了您的第二个问题,现在您可以在没有值的情况下调用 $table->addCell()
。
演示
require __DIR__ . '/vendor/autoload.php';
$document = new \PhpOffice\PhpWord\PhpWord();
$section = $document->addSection();
// This list **does** get rendered in the ODT file
$section->addListItem('Employee ID: 98765');
$section->addListItem('First Name: John');
$section->addListItem('Last Name: Doe');
$section->addListItem('SSN: 12345');
$table = $section->addTable();
$table->addRow();
$table->addCell()->addText('SSN');
$table->addCell()->addText('Email');
$table->addCell()->addText('Phone No');
$table->addRow();
$table->addCell()->addText('12345');
$table->addCell()->addText('jd@example.com');
$table->addCell()->addText('999 1234');
// Save the document as DOCX
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($document, 'Word2007');
$objWriter->save('document.docx');
// Save the document as ODT
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($document, 'ODText');
$objWriter->save('document.odt');