Skip to content

Commit aa151c4

Browse files
author
Bas-Jan 't Jong
committed
Added function to add elements via HTML
1 parent e9c548e commit aa151c4

File tree

2 files changed

+247
-0
lines changed

2 files changed

+247
-0
lines changed

samples/Sample_26_Html.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
include_once 'Sample_Header.php';
3+
4+
// New Word Document
5+
echo date('H:i:s') , ' Create new PhpWord object' , EOL;
6+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
7+
8+
$section = $phpWord->addSection();
9+
$html='<h1>Adding element via HTML</h1>';
10+
$html.='<p>Some well formed HTML snippet needs to be used</p>';
11+
$html.='<p>With for example <strong>some <em>inline</em> formatting</strong>';
12+
13+
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html);
14+
15+
// Save file
16+
echo write($phpWord, basename(__FILE__, '.php'), $writers);
17+
if (!CLI) {
18+
include_once 'Sample_Footer.php';
19+
}

src/PhpWord/Shared/Html.php

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
<?php
2+
/**
3+
* This file is part of PHPWord - A pure PHP library for reading and writing
4+
* word processing documents.
5+
*
6+
* PHPWord is free software distributed under the terms of the GNU Lesser
7+
* General Public License version 3 as published by the Free Software Foundation.
8+
*
9+
* For the full copyright and license information, please read the LICENSE
10+
* file that was distributed with this source code. For the full list of
11+
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
12+
*
13+
* @link https://github.com/PHPOffice/PHPWord
14+
* @copyright 2010-2014 PHPWord contributors
15+
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16+
*/
17+
18+
namespace PhpOffice\PhpWord\Shared;
19+
20+
/**
21+
* Common Html functions
22+
*/
23+
class Html
24+
{
25+
26+
/**
27+
* add HTML parts
28+
*
29+
* @param $object where the parts need to be added
30+
* @param $html the code to parse
31+
*
32+
*/
33+
public static function addHtml($object, $html, $stylesheet = '')
34+
{
35+
/*
36+
* @todo parse $stylesheet for default styles. Should result in an array based on id, class and element,
37+
* which could be applied when such an element occurs in the parseNode function.
38+
*/
39+
$html = str_replace(array("\n","\r"), '', $html);
40+
41+
$dom = new \DOMDocument();
42+
$dom->preserveWhiteSpace = true;
43+
$dom->loadXML('<body>' . html_entity_decode($html) . '</body>');
44+
45+
$node = $dom->getElementsByTagName('body');
46+
47+
self::parseNode($node->item(0), $object);
48+
}
49+
50+
/**
51+
* parse Inline style of a node
52+
*
53+
* @param $node node to check on attributes and to compile a style array
54+
* @param $style is supplied, the inline style attributes are added to the already existing style
55+
*
56+
*/
57+
protected static function parseInlineStyle($node, $style = array())
58+
{
59+
if ($node->nodeType == XML_ELEMENT_NODE) {
60+
$attributes = $node->attributes; // get all the attributes(eg: id, class)
61+
62+
foreach ($attributes as $attribute) {
63+
switch ($attribute->name) {
64+
case 'style':
65+
$properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;"));
66+
foreach ($properties as $property) {
67+
list ($cKey, $cValue) = explode(':', $property, 2);
68+
$cValue = trim($cValue);
69+
switch (trim($cKey)) {
70+
case 'text-decoration':
71+
switch ($cValue) {
72+
case 'underline':
73+
$style['underline'] = 'single';
74+
break;
75+
case 'line-through':
76+
$style['strikethrough'] = true;
77+
break;
78+
}
79+
break;
80+
case 'text-align':
81+
$style['align'] = $cValue;
82+
break;
83+
case 'color':
84+
$style['color'] = trim($cValue, "#");
85+
break;
86+
case 'background-color':
87+
$style['bgColor'] = trim($cValue, "#");
88+
break;
89+
}
90+
}
91+
break;
92+
}
93+
}
94+
}
95+
return $style;
96+
}
97+
98+
/**
99+
* parse a node and add a corresponding element to the object
100+
*
101+
* @param $node node to parse
102+
* @param $object object to add an element corresponding with the node
103+
* @param $styles array with all styles
104+
* @param $data array to transport data to a next level in the DOM tree, for example level of listitems
105+
*
106+
*/
107+
protected static function parseNode($node, $object, $styles = array('fontStyle' => array(), 'paragraphStyle' => array(), 'listStyle' => array()), $data = array())
108+
{
109+
$newobject = null;
110+
switch ($node->nodeName) {
111+
case 'p':
112+
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
113+
$newobject = $object->addTextRun($styles['paragraphStyle']);
114+
break;
115+
116+
/*
117+
* @todo Think of a clever way of defining header styles, now it is only based on the assumption, that
118+
* Heading1 - Heading6 are already defined somewhere
119+
*/
120+
case 'h1':
121+
$styles['paragraphStyle'] = 'Heading1';
122+
$newobject = $object->addTextRun($styles['paragraphStyle']);
123+
break;
124+
case 'h2':
125+
$styles['paragraphStyle'] = 'Heading2';
126+
$newobject = $object->addTextRun($styles['paragraphStyle']);
127+
break;
128+
case 'h3':
129+
$styles['paragraphStyle'] = 'Heading3';
130+
$newobject = $object->addTextRun($styles['paragraphStyle']);
131+
break;
132+
case 'h4':
133+
$styles['paragraphStyle'] = 'Heading4';
134+
$newobject = $object->addTextRun($styles['paragraphStyle']);
135+
break;
136+
case 'h5':
137+
$styles['paragraphStyle'] = 'Heading5';
138+
$newobject = $object->addTextRun($styles['paragraphStyle']);
139+
break;
140+
case 'h6':
141+
$styles['paragraphStyle'] = 'Heading6';
142+
$newobject = $object->addTextRun($styles['paragraphStyle']);
143+
break;
144+
case '#text':
145+
$styles['fontStyle'] = self::parseInlineStyle($node, $styles['fontStyle']);
146+
$object->AddText($node->nodeValue, $styles['fontStyle'], $styles['paragraphStyle']);
147+
break;
148+
case 'strong':
149+
$styles['fontStyle']['bold'] = true;
150+
break;
151+
case 'em':
152+
$styles['fontStyle']['italic'] = true;
153+
break;
154+
case 'sup':
155+
$styles['fontStyle']['superScript'] = true;
156+
break;
157+
case 'sub':
158+
$styles['fontStyle']['subScript'] = true;
159+
break;
160+
161+
/*
162+
* @todo As soon as TableItem, RowItem and CellItem support relative width and height
163+
*/
164+
case 'table':
165+
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
166+
$newobject = $object->addTable();
167+
// if ($attributes->getNamedItem('width') !== null)$newobject->setWidth($attributes->getNamedItem('width')->value);
168+
break;
169+
case 'tr':
170+
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
171+
$newobject = $object->addRow();
172+
// if ($attributes->getNamedItem('height') !== null)$newobject->setHeight($attributes->getNamedItem('height')->value);
173+
break;
174+
case 'td':
175+
$styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']);
176+
// if ($attributes->getNamedItem('width') !== null)$newobject=$object->addCell($width=$attributes->getNamedItem('width')->value);
177+
// else $newobject=$object->addCell();
178+
$newobject = $object->addCell();
179+
break;
180+
case 'ul':
181+
if (isset($data['listdepth'])) {
182+
$data['listdepth'] ++;
183+
} else {
184+
$data['listdepth'] = 0;
185+
}
186+
$styles['listStyle']['listType'] = 3; // TYPE_BULLET_FILLED = 3;
187+
break;
188+
case 'ol':
189+
if (isset($data['listdepth'])) {
190+
$data['listdepth'] ++;
191+
} else {
192+
$data['listdepth'] = 0;
193+
}
194+
$styles['listStyle']['listType'] = 7; // TYPE_NUMBER = 7;
195+
break;
196+
197+
/*
198+
* @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes
199+
*/
200+
case 'li':
201+
$cNodes = $node->childNodes;
202+
if (count($cNodes) > 0) {
203+
foreach ($cNodes as $cNode) {
204+
if ($cNode->nodeName == '#text') {
205+
$text = $cNode->nodeValue;
206+
}
207+
}
208+
$object->addListItem($text, $data['listdepth'], $styles['fontStyle'], $styles['listStyle'], $styles['paragraphStyle']);
209+
}
210+
}
211+
212+
if ($newobject === null) {
213+
$newobject = $object;
214+
}
215+
216+
/*
217+
* @todo As soon as ListItem inherits from AbstractContainer or TextRun delete condition
218+
*/
219+
if ($node->nodeName != 'li') {
220+
$cNodes = $node->childNodes;
221+
if (count($cNodes) > 0) {
222+
foreach ($cNodes as $cNode) {
223+
self::parseNode($cNode, $newobject, $styles, $data);
224+
}
225+
}
226+
}
227+
}
228+
}

0 commit comments

Comments
 (0)