From 8eb72c976a66bdcb9c76ef3e9e63763fa43f0ab8 Mon Sep 17 00:00:00 2001
From: troosan
Date: Wed, 15 Nov 2017 22:49:13 +0100
Subject: [PATCH] add HTML table parsing
---
samples/Sample_26_Html.php | 14 ++
src/PhpWord/Shared/Converter.php | 53 +++---
src/PhpWord/Shared/Html.php | 158 +++++++++++++++---
src/PhpWord/Style/Border.php | 151 +++++++++++++++++
src/PhpWord/Style/Cell.php | 85 +++++++++-
src/PhpWord/Writer/Word2007/Style/Cell.php | 1 +
.../Writer/Word2007/Style/MarginBorder.php | 27 ++-
src/PhpWord/Writer/Word2007/Style/Shading.php | 6 +-
tests/PhpWord/Shared/HtmlTest.php | 16 +-
tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +-
10 files changed, 452 insertions(+), 61 deletions(-)
diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php
index 4235c946..8e6e9a33 100644
--- a/samples/Sample_26_Html.php
+++ b/samples/Sample_26_Html.php
@@ -14,6 +14,20 @@ $html .= '- Item 1
- Item 2
- Item 2.1
- Item 2.1Ordered (numbered) list:
';
$html .= '- Item 1
- Item 2
';
+$html .= '
+
+
+ | header a |
+ header b |
+ header c |
+
+
+
+ | 1 | 2 |
+ | 4 | 5 | 6 |
+
+
';
+
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html);
// Save file
diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php
index 43c2f299..bae8985d 100644
--- a/src/PhpWord/Shared/Converter.php
+++ b/src/PhpWord/Shared/Converter.php
@@ -296,25 +296,40 @@ class Converter
*/
public static function cssToPoint($value)
{
- preg_match('/^[+-]?([0-9]+.?[0-9]+)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches);
- $size = $matches[1];
- $unit = $matches[2];
-
- switch ($unit) {
- case 'pt':
- return $size;
- case 'px':
- return self::pixelToPoint($size);
- case 'cm':
- return self::cmToPoint($size);
- case 'mm':
- return self::cmToPoint($size / 10);
- case 'in':
- return self::inchToPoint($size);
- case 'pc':
- return self::picaToPoint($size);
- default:
- return null;
+ if ($value == '0') {
+ return 0;
}
+ if (preg_match('/^[+-]?([0-9]+\.?[0-9]*)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches)) {
+ $size = $matches[1];
+ $unit = $matches[2];
+
+ switch ($unit) {
+ case 'pt':
+ return $size;
+ case 'px':
+ return self::pixelToPoint($size);
+ case 'cm':
+ return self::cmToPoint($size);
+ case 'mm':
+ return self::cmToPoint($size / 10);
+ case 'in':
+ return self::inchToPoint($size);
+ case 'pc':
+ return self::picaToPoint($size);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Transforms a size in CSS format (eg. 10px, 10px, ...) to twips
+ *
+ * @param string $value
+ * @return float
+ */
+ public static function cssToTwip($value)
+ {
+ return self::pointToTwip(self::cssToPoint($value));
}
}
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index c4292eb4..7239a046 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -18,6 +18,8 @@
namespace PhpOffice\PhpWord\Shared;
use PhpOffice\PhpWord\Element\AbstractContainer;
+use PhpOffice\PhpWord\Element\Row;
+use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\SimpleType\Jc;
/**
@@ -99,7 +101,7 @@ class Html
protected static function parseNode($node, $element, $styles = array(), $data = array())
{
// Populate styles array
- $styleTypes = array('font', 'paragraph', 'list');
+ $styleTypes = array('font', 'paragraph', 'list', 'table', 'row', 'cell');
foreach ($styleTypes as $styleType) {
if (!isset($styles[$styleType])) {
$styles[$styleType] = array();
@@ -124,10 +126,11 @@ class Html
'u' => array('Property', null, null, $styles, null, 'underline', 'single'),
'sup' => array('Property', null, null, $styles, null, 'superScript', true),
'sub' => array('Property', null, null, $styles, null, 'subScript', true),
- 'span' => array('Property', null, null, $styles, null, 'span', $node),
- 'table' => array('Table', $node, $element, $styles, null, 'addTable', true),
- 'tr' => array('Table', $node, $element, $styles, null, 'addRow', true),
- 'td' => array('Table', $node, $element, $styles, null, 'addCell', true),
+ 'span' => array('Span', $node, null, $styles, null, null, null),
+ 'table' => array('Table', $node, $element, $styles, null, null, null),
+ 'tr' => array('Row', $node, $element, $styles, null, null, null),
+ 'td' => array('Cell', $node, $element, $styles, null, null, null),
+ 'th' => array('Cell', $node, $element, $styles, null, null, null),
'ul' => array('List', null, null, $styles, $data, 3, null),
'ol' => array('List', null, null, $styles, $data, 7, null),
'li' => array('ListItem', $node, $element, $styles, $data, null, null),
@@ -179,7 +182,7 @@ class Html
$cNodes = $node->childNodes;
if (count($cNodes) > 0) {
foreach ($cNodes as $cNode) {
- if ($element instanceof AbstractContainer) {
+ if ($element instanceof AbstractContainer || $element instanceof Table || $element instanceof Row) {
self::parseNode($cNode, $element, $styles, $data);
}
}
@@ -197,7 +200,7 @@ class Html
*/
private static function parseParagraph($node, $element, &$styles)
{
- $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']);
+ $styles['paragraph'] = self::recursiveParseStylesInHierarchy($node, $styles['paragraph']);
$newElement = $element->addTextRun($styles['paragraph']);
return $newElement;
@@ -231,7 +234,12 @@ class Html
*/
private static function parseText($node, $element, &$styles)
{
- $styles['font'] = self::parseInlineStyle($node, $styles['font']);
+ $styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']);
+
+ //alignment applies on paragraph, not on font. Let's copy it there
+ if (isset($styles['font']['alignment'])) {
+ $styles['paragraph']['alignment'] = $styles['font']['alignment'];
+ }
if (is_callable(array($element, 'addText'))) {
$element->addText($node->nodeValue, $styles['font'], $styles['paragraph']);
@@ -247,16 +255,18 @@ class Html
*/
private static function parseProperty(&$styles, $argument1, $argument2)
{
- if ($argument1 !== 'span') {
- $styles['font'][$argument1] = $argument2;
- } else {
- if (!is_null($argument2->attributes)) {
- $nodeAttr = $argument2->attributes->getNamedItem('style');
- if (!is_null($nodeAttr) && property_exists($nodeAttr, 'value')) {
- $styles['font'] = self::parseStyle($nodeAttr, $styles['font']);
- }
- }
- }
+ $styles['font'][$argument1] = $argument2;
+ }
+
+ /**
+ * Parse span node
+ *
+ * @param \DOMNode $node
+ * @param array &$styles
+ */
+ private static function parseSpan($node, &$styles)
+ {
+ self::parseInlineStyle($node, $styles['font']);
}
/**
@@ -270,11 +280,11 @@ class Html
*
* @todo As soon as TableItem, RowItem and CellItem support relative width and height
*/
- private static function parseTable($node, $element, &$styles, $argument1)
+ private static function parseTable($node, $element, &$styles)
{
- $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']);
+ $elementStyles = self::parseInlineStyle($node, $styles['table']);
- $newElement = $element->$argument1();
+ $newElement = $element->addTable($elementStyles);
// $attributes = $node->attributes;
// if ($attributes->getNamedItem('width') !== null) {
@@ -291,6 +301,62 @@ class Html
return $newElement;
}
+ /**
+ * Parse a table row
+ *
+ * @param \DOMNode $node
+ * @param \PhpOffice\PhpWord\Element\Table $element
+ * @param array &$styles
+ * @return \PhpOffice\PhpWord\Element\AbstractContainer $element
+ */
+ private static function parseRow($node, $element, &$styles)
+ {
+ $rowStyles = self::parseInlineStyle($node, $styles['row']);
+ if ($node->parentNode->nodeName == 'thead') {
+ $rowStyles['tblHeader'] = true;
+ }
+
+ return $element->addRow(null, $rowStyles);
+ }
+
+ /**
+ * Parse table cell
+ *
+ * @param \DOMNode $node
+ * @param \PhpOffice\PhpWord\Element\Table $element
+ * @param array &$styles
+ * @return \PhpOffice\PhpWord\Element\AbstractContainer $element
+ */
+ private static function parseCell($node, $element, &$styles)
+ {
+ $cellStyles = self::recursiveParseStylesInHierarchy($node, $styles['cell']);
+
+ $colspan = $node->getAttribute('colspan');
+ if (!empty($colspan)) {
+ $cellStyles['gridSpan'] = $colspan - 0;
+ }
+
+ return $element->addCell(null, $cellStyles);
+ }
+
+ /**
+ * Recursively parses styles on parent nodes
+ * TODO if too slow, add caching of parent nodes, !! everything is static here so watch out for concurrency !!
+ *
+ * @param \DOMNode $node
+ * @param array &$styles
+ */
+ private static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style)
+ {
+ $parentStyle = self::parseInlineStyle($node, array());
+ $style = array_merge($parentStyle, $style);
+ if ($node->parentNode != null && XML_ELEMENT_NODE == $node->parentNode->nodeType) {
+ $style = self::recursiveParseStylesInHierarchy($node->parentNode, $style);
+ }
+
+ return $style;
+ }
+
/**
* Parse list node
*
@@ -400,9 +466,59 @@ class Html
}
$styles['italic'] = $tValue;
break;
+ case 'border-color':
+ $styles['color'] = trim($cValue, '#');
+ break;
+ case 'border-width':
+ $styles['borderSize'] = Converter::cssToPoint($cValue);
+ break;
+ case 'border-style':
+ $styles['borderStyle'] = self::mapBorderStyle($cValue);
+ break;
+ case 'width':
+ if (preg_match('/([0-9]+[a-z]+)/', $cValue, $matches)) {
+ $styles['width'] = Converter::cssToTwip($matches[1]);
+ $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_TWIP;
+ } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) {
+ $styles['width'] = $matches[1] * 50;
+ $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_PERCENT;
+ } elseif (preg_match('/([0-9]+)/', $cValue, $matches)) {
+ $styles['width'] = $matches[1];
+ $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_AUTO;
+ }
+ break;
+ case 'border':
+ if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+)\s+([a-z]+)/', $cValue, $matches)) {
+ $styles['borderSize'] = Converter::cssToPoint($matches[1]);
+ $styles['borderColor'] = trim($matches[2], '#');
+ $styles['borderStyle'] = self::mapBorderStyle($matches[3]);
+ }
+ break;
}
}
return $styles;
}
+
+ /**
+ * Transforms a CSS border style into a word border style
+ *
+ * @param string $cssBorderStyle
+ * @return null|string
+ */
+ private static function mapBorderStyle($cssBorderStyle)
+ {
+ if ($cssBorderStyle == null) {
+ return null;
+ }
+ switch ($cssBorderStyle) {
+ case 'none':
+ case 'dashed':
+ case 'dotted':
+ case 'double':
+ return $cssBorderStyle;
+ case 'solid':
+ return 'single';
+ }
+ }
}
diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php
index 5c62afcd..ab6aef18 100644
--- a/src/PhpWord/Style/Border.php
+++ b/src/PhpWord/Style/Border.php
@@ -36,6 +36,13 @@ class Border extends AbstractStyle
*/
protected $borderTopColor;
+ /**
+ * Border Top Style
+ *
+ * @var string
+ */
+ protected $borderTopStyle;
+
/**
* Border Left Size
*
@@ -50,6 +57,13 @@ class Border extends AbstractStyle
*/
protected $borderLeftColor;
+ /**
+ * Border Left Style
+ *
+ * @var string
+ */
+ protected $borderLeftStyle;
+
/**
* Border Right Size
*
@@ -64,6 +78,13 @@ class Border extends AbstractStyle
*/
protected $borderRightColor;
+ /**
+ * Border Right Style
+ *
+ * @var string
+ */
+ protected $borderRightStyle;
+
/**
* Border Bottom Size
*
@@ -78,6 +99,13 @@ class Border extends AbstractStyle
*/
protected $borderBottomColor;
+ /**
+ * Border Bottom Style
+ *
+ * @var string
+ */
+ protected $borderBottomStyle;
+
/**
* Get border size
*
@@ -140,6 +168,37 @@ class Border extends AbstractStyle
return $this;
}
+ /**
+ * Get border style
+ *
+ * @return string[]
+ */
+ public function getBorderStyle()
+ {
+ return array(
+ $this->getBorderTopStyle(),
+ $this->getBorderLeftStyle(),
+ $this->getBorderRightStyle(),
+ $this->getBorderBottomStyle(),
+ );
+ }
+
+ /**
+ * Set border style
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setBorderStyle($value = null)
+ {
+ $this->setBorderTopStyle($value);
+ $this->setBorderLeftStyle($value);
+ $this->setBorderRightStyle($value);
+ $this->setBorderBottomStyle($value);
+
+ return $this;
+ }
+
/**
* Get border top size
*
@@ -186,6 +245,29 @@ class Border extends AbstractStyle
return $this;
}
+ /**
+ * Get border top style
+ *
+ * @return string
+ */
+ public function getBorderTopStyle()
+ {
+ return $this->borderTopStyle;
+ }
+
+ /**
+ * Set border top Style
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setBorderTopStyle($value = null)
+ {
+ $this->borderTopStyle = $value;
+
+ return $this;
+ }
+
/**
* Get border left size
*
@@ -232,6 +314,29 @@ class Border extends AbstractStyle
return $this;
}
+ /**
+ * Get border left style
+ *
+ * @return string
+ */
+ public function getBorderLeftStyle()
+ {
+ return $this->borderLeftStyle;
+ }
+
+ /**
+ * Set border left style
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setBorderLeftStyle($value = null)
+ {
+ $this->borderLeftStyle = $value;
+
+ return $this;
+ }
+
/**
* Get border right size
*
@@ -278,6 +383,29 @@ class Border extends AbstractStyle
return $this;
}
+ /**
+ * Get border right style
+ *
+ * @return string
+ */
+ public function getBorderRightStyle()
+ {
+ return $this->borderRightStyle;
+ }
+
+ /**
+ * Set border right style
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setBorderRightStyle($value = null)
+ {
+ $this->borderRightStyle = $value;
+
+ return $this;
+ }
+
/**
* Get border bottom size
*
@@ -324,6 +452,29 @@ class Border extends AbstractStyle
return $this;
}
+ /**
+ * Get border bottom style
+ *
+ * @return string
+ */
+ public function getBorderBottomStyle()
+ {
+ return $this->borderBottomStyle;
+ }
+
+ /**
+ * Set border bottom style
+ *
+ * @param string $value
+ * @return self
+ */
+ public function setBorderBottomStyle($value = null)
+ {
+ $this->borderBottomStyle = $value;
+
+ return $this;
+ }
+
/**
* Check if any of the border is not null
*
diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php
index 0c4ca2e1..7fd5814d 100644
--- a/src/PhpWord/Style/Cell.php
+++ b/src/PhpWord/Style/Cell.php
@@ -32,13 +32,31 @@ class Cell extends Border
const VALIGN_BOTTOM = 'bottom';
const VALIGN_BOTH = 'both';
+ //Text direction constants
/**
- * Text direction constants
- *
- * @const string
+ * Left to Right, Top to Bottom
+ */
+ const TEXT_DIR_LRTB = 'lrTb';
+ /**
+ * Top to Bottom, Right to Left
+ */
+ const TEXT_DIR_TBRL = 'tbRl';
+ /**
+ * Bottom to Top, Left to Right
*/
const TEXT_DIR_BTLR = 'btLr';
- const TEXT_DIR_TBRL = 'tbRl';
+ /**
+ * Left to Right, Top to Bottom Rotated
+ */
+ const TEXT_DIR_LRTBV = 'lrTbV';
+ /**
+ * Top to Bottom, Right to Left Rotated
+ */
+ const TEXT_DIR_TBRLV = 'tbRlV';
+ /**
+ * Top to Bottom, Left to Right Rotated
+ */
+ const TEXT_DIR_TBLRV = 'tbLrV';
/**
* Vertical merge (rowspan) constants
@@ -93,6 +111,20 @@ class Cell extends Border
*/
private $shading;
+ /**
+ * Width
+ *
+ * @var int
+ */
+ private $width;
+
+ /**
+ * Width type
+ *
+ * @var string
+ */
+ private $widthType = Table::WIDTH_TWIP;
+
/**
* Get vertical align.
*
@@ -236,6 +268,51 @@ class Cell extends Border
return $this;
}
+ /**
+ * Get cell width
+ *
+ * @return int
+ */
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ /**
+ * Set cell width
+ *
+ * @param int $value
+ * @return self
+ */
+ public function setWidth($value)
+ {
+ $this->setIntVal($value);
+
+ return $this;
+ }
+
+ /**
+ * Get width type
+ *
+ * @return string
+ */
+ public function getWidthType()
+ {
+ return $this->widthType;
+ }
+
+ /**
+ * Set width type
+ *
+ * @param string $value
+ */
+ public function setWidthType($value)
+ {
+ $this->widthType = $this->setEnumVal($value, array(Table::WIDTH_AUTO, Table::WIDTH_PERCENT, Table::WIDTH_TWIP), Table::WIDTH_TWIP);
+
+ return $this;
+ }
+
/**
* Get default border color
*
diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php
index c2cf1c7c..82944d2c 100644
--- a/src/PhpWord/Writer/Word2007/Style/Cell.php
+++ b/src/PhpWord/Writer/Word2007/Style/Cell.php
@@ -65,6 +65,7 @@ class Cell extends AbstractStyle
$styleWriter = new MarginBorder($xmlWriter);
$styleWriter->setSizes($style->getBorderSize());
$styleWriter->setColors($style->getBorderColor());
+ $styleWriter->setStyles($style->getBorderStyle());
$styleWriter->setAttributes(array('defaultColor' => CellStyle::DEFAULT_BORDER_COLOR));
$styleWriter->write();
diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php
index 3d877384..5c3ecde2 100644
--- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php
+++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php
@@ -40,6 +40,13 @@ class MarginBorder extends AbstractStyle
*/
private $colors = array();
+ /**
+ * Border styles
+ *
+ * @var string[]
+ */
+ private $styles = array();
+
/**
* Other attributes
*
@@ -62,7 +69,8 @@ class MarginBorder extends AbstractStyle
if (isset($this->colors[$i])) {
$color = $this->colors[$i];
}
- $this->writeSide($xmlWriter, $sides[$i], $this->sizes[$i], $color);
+ $style = isset($this->styles[$i]) ? $this->styles[$i] : 'single';
+ $this->writeSide($xmlWriter, $sides[$i], $this->sizes[$i], $color, $style);
}
}
}
@@ -74,8 +82,9 @@ class MarginBorder extends AbstractStyle
* @param string $side
* @param int $width
* @param string $color
+ * @param string $borderStyle
*/
- private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null)
+ private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null, $borderStyle = 'solid')
{
$xmlWriter->startElement('w:' . $side);
if (!empty($this->colors)) {
@@ -84,9 +93,9 @@ class MarginBorder extends AbstractStyle
$color = $this->attributes['defaultColor'];
}
}
- $xmlWriter->writeAttribute('w:val', 'single');
+ $xmlWriter->writeAttribute('w:val', $borderStyle);
$xmlWriter->writeAttribute('w:sz', $width);
- $xmlWriter->writeAttribute('w:color', $color);
+ $xmlWriter->writeAttributeIf($color != null, 'w:color', $color);
if (!empty($this->attributes)) {
if (isset($this->attributes['space'])) {
$xmlWriter->writeAttribute('w:space', $this->attributes['space']);
@@ -119,6 +128,16 @@ class MarginBorder extends AbstractStyle
$this->colors = $value;
}
+ /**
+ * Set border styles.
+ *
+ * @param string[] $value
+ */
+ public function setStyles($value)
+ {
+ $this->styles = $value;
+ }
+
/**
* Set attributes.
*
diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php
index a8e6592a..00680687 100644
--- a/src/PhpWord/Writer/Word2007/Style/Shading.php
+++ b/src/PhpWord/Writer/Word2007/Style/Shading.php
@@ -36,9 +36,9 @@ class Shading extends AbstractStyle
$xmlWriter = $this->getXmlWriter();
$xmlWriter->startElement('w:shd');
- $xmlWriter->writeAttribute('w:val', $style->getPattern());
- $xmlWriter->writeAttribute('w:color', $style->getColor());
- $xmlWriter->writeAttribute('w:fill', $style->getFill());
+ $xmlWriter->writeAttributeIf(!is_null($style->getPattern()), 'w:val', $style->getPattern());
+ $xmlWriter->writeAttributeIf(!is_null($style->getColor()), 'w:color', $style->getColor());
+ $xmlWriter->writeAttributeIf(!is_null($style->getFill()), 'w:fill', $style->getFill());
$xmlWriter->endElement();
}
}
diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php
index c50df5af..39db0acf 100644
--- a/tests/PhpWord/Shared/HtmlTest.php
+++ b/tests/PhpWord/Shared/HtmlTest.php
@@ -187,25 +187,23 @@ class HtmlTest extends \PHPUnit\Framework\TestCase
{
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
- $html = '
-
+ $html = '
- | a |
- b |
- c |
+ header a |
+ header b |
+ header c |
- | 1 | 2 |
+ | 1 | 2 |
| 4 | 5 | 6 |
';
Html::addHtml($section, $html);
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
-// echo $doc->printXml();
- $this->assertTrue($doc->elementExists('/w:document/w:body/w:p'));
-// $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:tbl/w:tr/w:tc'));
+ $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl'));
+ $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc'));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php
index 0f0b323a..aeceaebc 100644
--- a/tests/PhpWord/Writer/Word2007/ElementTest.php
+++ b/tests/PhpWord/Writer/Word2007/ElementTest.php
@@ -45,7 +45,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$elements = array(
'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun',
'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC',
- 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT',
+ 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT', 'Bookmark',
);
foreach ($elements as $element) {
$objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element;