commit
4fdc7b8e6e
|
|
@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers
|
|||
|
||||
## 0.11.0 - Not yet released
|
||||
|
||||
This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF reader were initiated.
|
||||
This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemeted. RTF and HTML reader were initiated.
|
||||
|
||||
### Features
|
||||
|
||||
|
|
@ -33,6 +33,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four
|
|||
- RTF Reader: Basic RTF reader - @ivanlanin GH-72 GH-252
|
||||
- Element: New `Line` element - @basjan GH-253
|
||||
- Title: Ability to apply numbering in heading - @ivanlanin GH-193
|
||||
- HTML Reader: Basic HTML reader - @ivanlanin GH-80 GH-254
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
|
|
|||
110
docs/intro.rst
110
docs/intro.rst
|
|
@ -117,61 +117,61 @@ Writers
|
|||
Readers
|
||||
~~~~~~~
|
||||
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| Features | | DOCX | ODT | RTF |
|
||||
+===========================+======================+========+=======+=======+
|
||||
| **Document Properties** | Standard | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Custom | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| **Element Type** | Text | ✓ | ✓ | ✓ |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Text Run | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Title | ✓ | ✓ | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Link | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Preserve Text | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Text Break | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Page Break | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | List | ✓ | ✓ | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Table | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Image | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Object | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Watermark | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Table of Contents | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Header | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Footer | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Footnote | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Endnote | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| **Graphs** | 2D basic graphs | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | 2D advanced graphs | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | 3D graphs | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| **Math** | OMML support | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | MathML support | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| **Bonus** | Encryption | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
| | Protection | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| Features | | DOCX | ODT | RTF | HTML |
|
||||
+===========================+======================+========+=======+=======+=======+
|
||||
| **Document Properties** | Standard | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Custom | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Text Run | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Title | ✓ | ✓ | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Link | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Preserve Text | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Text Break | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Page Break | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | List | ✓ | ✓ | | ✓ |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Table | ✓ | | | ✓ |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Image | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Object | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Watermark | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Table of Contents | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Header | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Footer | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Footnote | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Endnote | ✓ | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| **Graphs** | 2D basic graphs | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | 2D advanced graphs | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | 3D graphs | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| **Math** | OMML support | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | MathML support | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| **Bonus** | Encryption | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
| | Protection | | | | |
|
||||
+---------------------------+----------------------+--------+-------+-------+-------+
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
|
|
|||
|
|
@ -111,34 +111,34 @@ Below are the supported features for each file formats.
|
|||
|
||||
### Readers
|
||||
|
||||
| Features | | DOCX | ODT | RTF |
|
||||
|-------------------------|--------------------|------|-----|-----|
|
||||
| **Document Properties** | Standard | ✓ | | |
|
||||
| | Custom | ✓ | | |
|
||||
| **Element Type** | Text | ✓ | ✓ | ✓ |
|
||||
| | Text Run | ✓ | | |
|
||||
| | Title | ✓ | ✓ | |
|
||||
| | Link | ✓ | | |
|
||||
| | Preserve Text | ✓ | | |
|
||||
| | Text Break | ✓ | | |
|
||||
| | Page Break | ✓ | | |
|
||||
| | List | ✓ | ✓ | |
|
||||
| | Table | ✓ | | |
|
||||
| | Image | ✓ | | |
|
||||
| | Object | | | |
|
||||
| | Watermark | | | |
|
||||
| | Table of Contents | | | |
|
||||
| | Header | ✓ | | |
|
||||
| | Footer | ✓ | | |
|
||||
| | Footnote | ✓ | | |
|
||||
| | Endnote | ✓ | | |
|
||||
| **Graphs** | 2D basic graphs | | | |
|
||||
| | 2D advanced graphs | | | |
|
||||
| | 3D graphs | | | |
|
||||
| **Math** | OMML support | | | |
|
||||
| | MathML support | | | |
|
||||
| **Bonus** | Encryption | | | |
|
||||
| | Protection | | | |
|
||||
| Features | | DOCX | ODT | RTF | HTML|
|
||||
|-------------------------|--------------------|------|-----|-----|-----|
|
||||
| **Document Properties** | Standard | ✓ | | | |
|
||||
| | Custom | ✓ | | | |
|
||||
| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ |
|
||||
| | Text Run | ✓ | | | |
|
||||
| | Title | ✓ | ✓ | | |
|
||||
| | Link | ✓ | | | |
|
||||
| | Preserve Text | ✓ | | | |
|
||||
| | Text Break | ✓ | | | |
|
||||
| | Page Break | ✓ | | | |
|
||||
| | List | ✓ | ✓ | | ✓ |
|
||||
| | Table | ✓ | | | ✓ |
|
||||
| | Image | ✓ | | | |
|
||||
| | Object | | | | |
|
||||
| | Watermark | | | | |
|
||||
| | Table of Contents | | | | |
|
||||
| | Header | ✓ | | | |
|
||||
| | Footer | ✓ | | | |
|
||||
| | Footnote | ✓ | | | |
|
||||
| | Endnote | ✓ | | | |
|
||||
| **Graphs** | 2D basic graphs | | | | |
|
||||
| | 2D advanced graphs | | | | |
|
||||
| | 3D graphs | | | | |
|
||||
| **Math** | OMML support | | | | |
|
||||
| | MathML support | | | | |
|
||||
| **Bonus** | Encryption | | | | |
|
||||
| | Protection | | | | |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord();
|
|||
$section = $phpWord->addSection();
|
||||
$html = '<h1>Adding element via HTML</h1>';
|
||||
$html .= '<p>Some well formed HTML snippet needs to be used</p>';
|
||||
$html .= '<p>With for example <strong>some <em>inline</em> formatting</strong></p>';
|
||||
$html .= '<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>';
|
||||
$html .= '<p>Unordered (bulleted) list:</p>';
|
||||
$html .= '<ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul>';
|
||||
$html .= '<p>Ordered (numbered) list:</p>';
|
||||
$html .= '<ol><li>Item 1</li><li>Item 2</li></ol>';
|
||||
|
||||
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
include_once 'Sample_Header.php';
|
||||
|
||||
// Read contents
|
||||
$name = basename(__FILE__, '.php');
|
||||
$source = realpath(__DIR__ . "/resources/{$name}.html");
|
||||
|
||||
echo date('H:i:s'), " Reading contents from `{$source}`", EOL;
|
||||
$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'HTML');
|
||||
|
||||
// Save file
|
||||
echo write($phpWord, basename(__FILE__, '.php'), $writers);
|
||||
if (!CLI) {
|
||||
include_once 'Sample_Footer.php';
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>PHPWord</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Adding element via HTML</h1>
|
||||
<p>Some well formed HTML snippet needs to be used</p>
|
||||
<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>
|
||||
<p>Unordered (bulleted) list:</p>
|
||||
<ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul>
|
||||
<p>Ordered (numbered) list:</p>
|
||||
<ol><li>Item 1</li><li>Item 2</li></ol>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -51,7 +51,7 @@ abstract class IOFactory
|
|||
*/
|
||||
public static function createReader($name = 'Word2007')
|
||||
{
|
||||
if (!in_array($name, array('ReaderInterface', 'Word2007', 'ODText', 'RTF'))) {
|
||||
if (!in_array($name, array('ReaderInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) {
|
||||
throw new Exception("\"{$name}\" is not a valid reader.");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @link https://github.com/PHPOffice/PHPWord
|
||||
* @copyright 2010-2014 PHPWord contributors
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Reader;
|
||||
|
||||
use PhpOffice\PhpWord\PhpWord;
|
||||
use PhpOffice\PhpWord\Shared\Html as HTMLParser;
|
||||
|
||||
/**
|
||||
* HTML Reader class
|
||||
*
|
||||
* @since 0.11.0
|
||||
*/
|
||||
class HTML extends AbstractReader implements ReaderInterface
|
||||
{
|
||||
/**
|
||||
* Loads PhpWord from file
|
||||
*
|
||||
* @param string $docFile
|
||||
* @throws \Exception
|
||||
* @return \PhpOffice\PhpWord\PhpWord
|
||||
*/
|
||||
public function load($docFile)
|
||||
{
|
||||
$phpWord = new PhpWord();
|
||||
|
||||
if ($this->canRead($docFile)) {
|
||||
$section = $phpWord->addSection();
|
||||
HTMLParser::addHtml($section, file_get_contents($docFile), true);
|
||||
} else {
|
||||
throw new \Exception("Cannot read {$docFile}.");
|
||||
}
|
||||
|
||||
return $phpWord;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,12 @@
|
|||
|
||||
namespace PhpOffice\PhpWord\Shared;
|
||||
|
||||
use PhpOffice\PhpWord\Element\AbstractContainer;
|
||||
|
||||
/**
|
||||
* Common Html functions
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
|
||||
*/
|
||||
class Html
|
||||
{
|
||||
|
|
@ -27,34 +31,41 @@ class Html
|
|||
*
|
||||
* Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter
|
||||
*
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $object Where the parts need to be added
|
||||
* @param string $html the code to parse
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added
|
||||
* @param string $html The code to parse
|
||||
* @param bool $fullHTML If it's a full HTML, no need to add 'body' tag
|
||||
*/
|
||||
public static function addHtml($object, $html)
|
||||
public static function addHtml($element, $html, $fullHTML = false)
|
||||
{
|
||||
/*
|
||||
* @todo parse $stylesheet for default styles. Should result in an array based on id, class and element,
|
||||
* which could be applied when such an element occurs in the parseNode function.
|
||||
*/
|
||||
$html = str_replace(array("\n", "\r"), '', $html);
|
||||
|
||||
// Preprocess: remove all line ends, decode HTML entity, and add body tag for HTML fragments
|
||||
$html = str_replace(array("\n", "\r"), '', $html);
|
||||
$html = html_entity_decode($html);
|
||||
if ($fullHTML === false) {
|
||||
$html = '<body>' . $html . '</body>';
|
||||
}
|
||||
|
||||
// Load DOM
|
||||
$dom = new \DOMDocument();
|
||||
$dom->preserveWhiteSpace = true;
|
||||
$dom->loadXML('<body>' . html_entity_decode($html) . '</body>');
|
||||
|
||||
$dom->loadXML($html);
|
||||
$node = $dom->getElementsByTagName('body');
|
||||
|
||||
self::parseNode($node->item(0), $object);
|
||||
self::parseNode($node->item(0), $element);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse Inline style of a node
|
||||
*
|
||||
* @param \DOMNode $node Node to check on attributes and to compile a style array
|
||||
* @param array $style is supplied, the inline style attributes are added to the already existing style
|
||||
* @param array $styles is supplied, the inline style attributes are added to the already existing style
|
||||
* @return array
|
||||
*/
|
||||
protected static function parseInlineStyle($node, $style = array())
|
||||
protected static function parseInlineStyle($node, $styles = array())
|
||||
{
|
||||
if ($node->nodeType == XML_ELEMENT_NODE) {
|
||||
$attributes = $node->attributes; // get all the attributes(eg: id, class)
|
||||
|
|
@ -62,191 +73,295 @@ class Html
|
|||
foreach ($attributes as $attribute) {
|
||||
switch ($attribute->name) {
|
||||
case 'style':
|
||||
$properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;"));
|
||||
foreach ($properties as $property) {
|
||||
list ($cKey, $cValue) = explode(':', $property, 2);
|
||||
$cValue = trim($cValue);
|
||||
switch (trim($cKey)) {
|
||||
case 'text-decoration':
|
||||
switch ($cValue) {
|
||||
case 'underline':
|
||||
$style['underline'] = 'single';
|
||||
break;
|
||||
case 'line-through':
|
||||
$style['strikethrough'] = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'text-align':
|
||||
$style['align'] = $cValue;
|
||||
break;
|
||||
case 'color':
|
||||
$style['color'] = trim($cValue, "#");
|
||||
break;
|
||||
case 'background-color':
|
||||
$style['bgColor'] = trim($cValue, "#");
|
||||
break;
|
||||
}
|
||||
}
|
||||
$styles = self::parseStyle($attribute, $styles);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
return $styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a node and add a corresponding element to the object
|
||||
* Parse a node and add a corresponding element to the parent element
|
||||
*
|
||||
* @param \DOMNode $node node to parse
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $object object to add an element corresponding with the node
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element object to add an element corresponding with the node
|
||||
* @param array $styles Array with all styles
|
||||
* @param array $data Array to transport data to a next level in the DOM tree, for example level of listitems
|
||||
*/
|
||||
protected static function parseNode(
|
||||
$node,
|
||||
$object,
|
||||
$styles = array('fontStyle' => array(), 'paragraphStyle' => array(), 'listStyle' => array()),
|
||||
$data = array()
|
||||
) {
|
||||
$newobject = null;
|
||||
switch ($node->nodeName) {
|
||||
case 'p':
|
||||
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
|
||||
$newobject = $object->addTextRun($styles['paragraphStyle']);
|
||||
break;
|
||||
|
||||
/**
|
||||
* @todo Think of a clever way of defining header styles, now it is only based on the assumption, that
|
||||
* Heading1 - Heading6 are already defined somewhere
|
||||
*/
|
||||
case 'h1':
|
||||
$styles['paragraphStyle'] = 'Heading1';
|
||||
$newobject = $object->addTextRun($styles['paragraphStyle']);
|
||||
break;
|
||||
case 'h2':
|
||||
$styles['paragraphStyle'] = 'Heading2';
|
||||
$newobject = $object->addTextRun($styles['paragraphStyle']);
|
||||
break;
|
||||
case 'h3':
|
||||
$styles['paragraphStyle'] = 'Heading3';
|
||||
$newobject = $object->addTextRun($styles['paragraphStyle']);
|
||||
break;
|
||||
case 'h4':
|
||||
$styles['paragraphStyle'] = 'Heading4';
|
||||
$newobject = $object->addTextRun($styles['paragraphStyle']);
|
||||
break;
|
||||
case 'h5':
|
||||
$styles['paragraphStyle'] = 'Heading5';
|
||||
$newobject = $object->addTextRun($styles['paragraphStyle']);
|
||||
break;
|
||||
case 'h6':
|
||||
$styles['paragraphStyle'] = 'Heading6';
|
||||
$newobject = $object->addTextRun($styles['paragraphStyle']);
|
||||
break;
|
||||
case '#text':
|
||||
$styles['fontStyle'] = self::parseInlineStyle($node, $styles['fontStyle']);
|
||||
if (method_exists($object, 'addText')) {
|
||||
$object->addText($node->nodeValue, $styles['fontStyle'], $styles['paragraphStyle']);
|
||||
}
|
||||
break;
|
||||
case 'strong':
|
||||
$styles['fontStyle']['bold'] = true;
|
||||
break;
|
||||
case 'em':
|
||||
$styles['fontStyle']['italic'] = true;
|
||||
break;
|
||||
case 'sup':
|
||||
$styles['fontStyle']['superScript'] = true;
|
||||
break;
|
||||
case 'sub':
|
||||
$styles['fontStyle']['subScript'] = true;
|
||||
break;
|
||||
|
||||
/**
|
||||
* @todo As soon as TableItem, RowItem and CellItem support relative width and height
|
||||
*/
|
||||
case 'table':
|
||||
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
|
||||
$newobject = $object->addTable();
|
||||
// if ($attributes->getNamedItem('width') !== null) {
|
||||
// $newobject->setWidth($attributes->getNamedItem('width')->value);
|
||||
// }
|
||||
break;
|
||||
case 'tr':
|
||||
/** @var \PhpOffice\PhpWord\Element\Table $object Type hint */
|
||||
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
|
||||
$newobject = $object->addRow();
|
||||
// if ($attributes->getNamedItem('height') !== null) {
|
||||
// $newobject->setHeight($attributes->getNamedItem('height')->value);
|
||||
// }
|
||||
break;
|
||||
case 'td':
|
||||
/** @var \PhpOffice\PhpWord\Element\Row $object Type hint */
|
||||
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
|
||||
// if ($attributes->getNamedItem('width') !== null) {
|
||||
// $newobject=$object->addCell($width=$attributes->getNamedItem('width')->value);
|
||||
// } else {
|
||||
// $newobject=$object->addCell();
|
||||
// }
|
||||
$newobject = $object->addCell();
|
||||
break;
|
||||
case 'ul':
|
||||
if (isset($data['listdepth'])) {
|
||||
$data['listdepth'] ++;
|
||||
} else {
|
||||
$data['listdepth'] = 0;
|
||||
}
|
||||
$styles['listStyle']['listType'] = 3; // TYPE_BULLET_FILLED = 3;
|
||||
break;
|
||||
case 'ol':
|
||||
if (isset($data['listdepth'])) {
|
||||
$data['listdepth'] ++;
|
||||
} else {
|
||||
$data['listdepth'] = 0;
|
||||
}
|
||||
$styles['listStyle']['listType'] = 7; // TYPE_NUMBER = 7;
|
||||
break;
|
||||
|
||||
/**
|
||||
* @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes
|
||||
*/
|
||||
case 'li':
|
||||
$cNodes = $node->childNodes;
|
||||
if (count($cNodes) > 0) {
|
||||
$text = '';
|
||||
foreach ($cNodes as $cNode) {
|
||||
if ($cNode->nodeName == '#text') {
|
||||
$text = $cNode->nodeValue;
|
||||
}
|
||||
}
|
||||
$object->addListItem(
|
||||
$text,
|
||||
$data['listdepth'],
|
||||
$styles['fontStyle'],
|
||||
$styles['listStyle'],
|
||||
$styles['paragraphStyle']
|
||||
);
|
||||
}
|
||||
protected static function parseNode($node, $element, $styles = array(), $data = array())
|
||||
{
|
||||
// Populate styles array
|
||||
$styleTypes = array('font', 'paragraph', 'list');
|
||||
foreach ($styleTypes as $styleType) {
|
||||
if (!isset($styles[$styleType])) {
|
||||
$styles[$styleType] = array();
|
||||
}
|
||||
}
|
||||
|
||||
if ($newobject === null) {
|
||||
$newobject = $object;
|
||||
// Node mapping table
|
||||
$nodes = array(
|
||||
// $method $node $element $styles $data $argument1 $argument2
|
||||
'p' => array('Paragraph', $node, $element, $styles, null, null, null),
|
||||
'h1' => array('Heading', null, $element, $styles, null, 'Heading1', null),
|
||||
'h2' => array('Heading', null, $element, $styles, null, 'Heading2', null),
|
||||
'h3' => array('Heading', null, $element, $styles, null, 'Heading3', null),
|
||||
'h4' => array('Heading', null, $element, $styles, null, 'Heading4', null),
|
||||
'h5' => array('Heading', null, $element, $styles, null, 'Heading5', null),
|
||||
'h6' => array('Heading', null, $element, $styles, null, 'Heading6', null),
|
||||
'#text' => array('Text', $node, $element, $styles, null, null, null),
|
||||
'strong' => array('Property', null, null, $styles, null, 'bold', true),
|
||||
'em' => array('Property', null, null, $styles, null, 'italic', true),
|
||||
'sup' => array('Property', null, null, $styles, null, 'superScript', true),
|
||||
'sub' => array('Property', null, null, $styles, null, 'subScript', true),
|
||||
'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),
|
||||
'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),
|
||||
);
|
||||
|
||||
$newElement = null;
|
||||
$keys = array('node', 'element', 'styles', 'data', 'argument1', 'argument2');
|
||||
|
||||
if (array_key_exists($node->nodeName, $nodes)) {
|
||||
|
||||
// Execute method based on node mapping table and return $newElement or null
|
||||
// Arguments are passed by reference
|
||||
$arguments = array();
|
||||
$args = array();
|
||||
list($method, $args[0], $args[1], $args[2], $args[3], $args[4], $args[5]) = $nodes[$node->nodeName];
|
||||
for ($i = 0; $i <= 5; $i++) {
|
||||
if ($args[$i] !== null) {
|
||||
$arguments[$keys[$i]] = &$args[$i];
|
||||
}
|
||||
}
|
||||
$method = "parse{$method}";
|
||||
$newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments);
|
||||
|
||||
// Retrieve back variables from arguments
|
||||
foreach ($keys as $key) {
|
||||
if (array_key_exists($key, $arguments)) {
|
||||
$$key = $arguments[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo As soon as ListItem inherits from AbstractContainer or TextRun delete condition
|
||||
*/
|
||||
if ($newElement === null) {
|
||||
$newElement = $element;
|
||||
}
|
||||
|
||||
self::parseChildNodes($node, $newElement, $styles, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse child nodes
|
||||
*
|
||||
* @param \DOMNode $node
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||
* @param array $styles
|
||||
* @param array $data
|
||||
*/
|
||||
private static function parseChildNodes($node, $element, $styles, $data)
|
||||
{
|
||||
if ($node->nodeName != 'li') {
|
||||
$cNodes = $node->childNodes;
|
||||
if (count($cNodes) > 0) {
|
||||
foreach ($cNodes as $cNode) {
|
||||
if ($newobject instanceof \PhpOffice\PhpWord\Element\AbstractContainer) {
|
||||
self::parseNode($cNode, $newobject, $styles, $data);
|
||||
if ($element instanceof AbstractContainer) {
|
||||
self::parseNode($cNode, $element, $styles, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse paragraph node
|
||||
*
|
||||
* @param \DOMNode $node
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||
* @param array $styles
|
||||
* @return \PhpOffice\PhpWord\Element\TextRun
|
||||
*/
|
||||
private static function parseParagraph($node, $element, &$styles)
|
||||
{
|
||||
$styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']);
|
||||
$newElement = $element->addTextRun($styles['paragraph']);
|
||||
|
||||
return $newElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse heading node
|
||||
*
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||
* @param array $styles
|
||||
* @param string $argument1 Name of heading style
|
||||
* @return \PhpOffice\PhpWord\Element\TextRun
|
||||
*
|
||||
* @todo Think of a clever way of defining header styles, now it is only based on the assumption, that
|
||||
* Heading1 - Heading6 are already defined somewhere
|
||||
*/
|
||||
private static function parseHeading($element, &$styles, $argument1)
|
||||
{
|
||||
$styles['paragraph'] = $argument1;
|
||||
$newElement = $element->addTextRun($styles['paragraph']);
|
||||
|
||||
return $newElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse text node
|
||||
*
|
||||
* @param \DOMNode $node
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||
* @param array $styles
|
||||
* @return null
|
||||
*/
|
||||
private static function parseText($node, $element, &$styles)
|
||||
{
|
||||
$styles['font'] = self::parseInlineStyle($node, $styles['font']);
|
||||
if (method_exists($element, 'addText')) {
|
||||
$element->addText($node->nodeValue, $styles['font'], $styles['paragraph']);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse property node
|
||||
*
|
||||
* @param array $styles
|
||||
* @param string $argument1 Style name
|
||||
* @param string $argument2 Style value
|
||||
* @return null
|
||||
*/
|
||||
private static function parseProperty(&$styles, $argument1, $argument2)
|
||||
{
|
||||
$styles['font'][$argument1] = $argument2;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse table node
|
||||
*
|
||||
* @param \DOMNode $node
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||
* @param array $styles
|
||||
* @param string $argument1 Method name
|
||||
* @return \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||
*
|
||||
* @todo As soon as TableItem, RowItem and CellItem support relative width and height
|
||||
*/
|
||||
private static function parseTable($node, $element, &$styles, $argument1)
|
||||
{
|
||||
$styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']);
|
||||
|
||||
$newElement = $element->$argument1();
|
||||
|
||||
// $attributes = $node->attributes;
|
||||
// if ($attributes->getNamedItem('width') !== null) {
|
||||
// $newElement->setWidth($attributes->getNamedItem('width')->value);
|
||||
// }
|
||||
|
||||
// if ($attributes->getNamedItem('height') !== null) {
|
||||
// $newElement->setHeight($attributes->getNamedItem('height')->value);
|
||||
// }
|
||||
// if ($attributes->getNamedItem('width') !== null) {
|
||||
// $newElement=$element->addCell($width=$attributes->getNamedItem('width')->value);
|
||||
// }
|
||||
|
||||
return $newElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse list node
|
||||
*
|
||||
* @param array $styles
|
||||
* @param array $data
|
||||
* @param string $argument1 List type
|
||||
* @return null
|
||||
*/
|
||||
private static function parseList(&$styles, &$data, $argument1)
|
||||
{
|
||||
if (isset($data['listdepth'])) {
|
||||
$data['listdepth']++;
|
||||
} else {
|
||||
$data['listdepth'] = 0;
|
||||
}
|
||||
$styles['list']['listType'] = $argument1;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse list item node
|
||||
*
|
||||
* @param \DOMNode $node
|
||||
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||
* @param array $styles
|
||||
* @param array $data
|
||||
* @return null
|
||||
*
|
||||
* @todo This function is almost the same like `parseChildNodes`. Merged?
|
||||
* @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes
|
||||
*/
|
||||
private static function parseListItem($node, $element, &$styles, $data)
|
||||
{
|
||||
$cNodes = $node->childNodes;
|
||||
if (count($cNodes) > 0) {
|
||||
$text = '';
|
||||
foreach ($cNodes as $cNode) {
|
||||
if ($cNode->nodeName == '#text') {
|
||||
$text = $cNode->nodeValue;
|
||||
}
|
||||
}
|
||||
$element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse style
|
||||
*
|
||||
* @param \DOMAttr $attribute
|
||||
* @param array $styles
|
||||
* @return array
|
||||
*/
|
||||
private static function parseStyle($attribute, $styles)
|
||||
{
|
||||
$properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;"));
|
||||
foreach ($properties as $property) {
|
||||
list($cKey, $cValue) = explode(':', $property, 2);
|
||||
$cValue = trim($cValue);
|
||||
switch (trim($cKey)) {
|
||||
case 'text-decoration':
|
||||
switch ($cValue) {
|
||||
case 'underline':
|
||||
$styles['underline'] = 'single';
|
||||
break;
|
||||
case 'line-through':
|
||||
$styles['strikethrough'] = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'text-align':
|
||||
$styles['align'] = $cValue;
|
||||
break;
|
||||
case 'color':
|
||||
$styles['color'] = trim($cValue, "#");
|
||||
break;
|
||||
case 'background-color':
|
||||
$styles['bgColor'] = trim($cValue, "#");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $styles;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ class Paragraph extends AbstractStyle
|
|||
* reduce function call and increase cohesion between functions. Should be
|
||||
* implemented in all styles.
|
||||
*
|
||||
* @ignoreScrutinizerPatch
|
||||
* @return array
|
||||
*/
|
||||
public function getStyleValues()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||
* word processing documents.
|
||||
*
|
||||
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||
* General Public License version 3 as published by the Free Software Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please read the LICENSE
|
||||
* file that was distributed with this source code. For the full list of
|
||||
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||
*
|
||||
* @link https://github.com/PHPOffice/PHPWord
|
||||
* @copyright 2010-2014 PHPWord contributors
|
||||
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||
*/
|
||||
|
||||
namespace PhpOffice\PhpWord\Tests\Reader;
|
||||
|
||||
use PhpOffice\PhpWord\IOFactory;
|
||||
|
||||
/**
|
||||
* Test class for PhpOffice\PhpWord\Reader\HTML
|
||||
*
|
||||
* @coversDefaultClass \PhpOffice\PhpWord\Reader\HTML
|
||||
* @runTestsInSeparateProcesses
|
||||
*/
|
||||
class HTMLTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Test load
|
||||
*/
|
||||
public function testLoad()
|
||||
{
|
||||
$filename = __DIR__ . '/../_files/documents/reader.html';
|
||||
$phpWord = IOFactory::load($filename, 'HTML');
|
||||
$this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test load exception
|
||||
*
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage Cannot read
|
||||
*/
|
||||
public function testLoadException()
|
||||
{
|
||||
$filename = __DIR__ . '/../_files/documents/foo.html';
|
||||
IOFactory::load($filename, 'HTML');
|
||||
}
|
||||
}
|
||||
|
|
@ -58,8 +58,8 @@ class HtmlTest extends \PHPUnit_Framework_TestCase
|
|||
$section = new Section(1);
|
||||
$content = '';
|
||||
$content .= '<table><tr><th>Header</th><td>Content</td></tr></table>';
|
||||
$content .= '<ul><li>Bullet</li></ul>';
|
||||
$content .= '<ul><li>Bullet</li><ul><li>Bullet</li></ul></ul>';
|
||||
$content .= '<ol><li>Bullet</li></ol>';
|
||||
Html::addHtml($section, $content, null, array('listdepth' => 2));
|
||||
Html::addHtml($section, $content);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>PHPWord</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Adding element via HTML</h1>
|
||||
<p>Some well formed HTML snippet needs to be used</p>
|
||||
<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>
|
||||
<p>Unordered (bulleted) list:</p>
|
||||
<ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul>
|
||||
<p>Ordered (numbered) list:</p>
|
||||
<ol><li>Item 1</li><li>Item 2</li></ol>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue