22
22
23
23
/**
24
24
* Abstract part reader
25
+ *
26
+ * This class is inherited by ODText reader
25
27
*/
26
28
abstract class AbstractPart
27
29
{
30
+ /**
31
+ * Conversion method
32
+ *
33
+ * @const int
34
+ */
35
+ const READ_VALUE = 'attributeValue ' ; // Read attribute value
36
+ const READ_EQUAL = 'attributeEquals ' ; // Read `true` when attribute value equals specified value
37
+ const READ_TRUE = 'attributeTrue ' ; // Read `true` when element exists
38
+ const READ_FALSE = 'attributeFalse ' ; // Read `false` when element exists
39
+ const READ_SIZE = 'attributeMultiplyByTwo ' ; // Read special attribute value for Font::$size
40
+
28
41
/**
29
42
* Document file
30
43
*
@@ -145,66 +158,34 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, &$parent,
145
158
protected function readParagraphStyle (XMLReader $ xmlReader , \DOMElement $ domNode )
146
159
{
147
160
if (!$ xmlReader ->elementExists ('w:pPr ' , $ domNode )) {
148
- return '' ;
161
+ return null ;
149
162
}
150
163
151
- $ style = array ();
152
- $ mapping = array (
153
- 'w:pStyle ' => 'styleName ' ,
154
- 'w:ind ' => 'indent ' , 'w:spacing ' => 'spacing ' ,
155
- 'w:jc ' => 'align ' , 'w:basedOn ' => 'basedOn ' , 'w:next ' => 'next ' ,
156
- 'w:widowControl ' => 'widowControl ' , 'w:keepNext ' => 'keepNext ' ,
157
- 'w:keepLines ' => 'keepLines ' , 'w:pageBreakBefore ' => 'pageBreakBefore ' ,
164
+ $ styleNode = $ xmlReader ->getElement ('w:pPr ' , $ domNode );
165
+ $ styleDefs = array (
166
+ 'styleName ' => array (self ::READ_VALUE , 'w:pStyle ' ),
167
+ 'align ' => array (self ::READ_VALUE , 'w:jc ' ),
168
+ 'basedOn ' => array (self ::READ_VALUE , 'w:basedOn ' ),
169
+ 'next ' => array (self ::READ_VALUE , 'w:next ' ),
170
+ 'indent ' => array (self ::READ_VALUE , 'w:ind ' , 'w:left ' ),
171
+ 'hanging ' => array (self ::READ_VALUE , 'w:ind ' , 'w:hanging ' ),
172
+ 'spaceAfter ' => array (self ::READ_VALUE , 'w:spacing ' , 'w:after ' ),
173
+ 'spaceBefore ' => array (self ::READ_VALUE , 'w:spacing ' , 'w:before ' ),
174
+ 'widowControl ' => array (self ::READ_FALSE , 'w:widowControl ' ),
175
+ 'keepNext ' => array (self ::READ_TRUE , 'w:keepNext ' ),
176
+ 'keepLines ' => array (self ::READ_TRUE , 'w:keepLines ' ),
177
+ 'pageBreakBefore ' => array (self ::READ_TRUE , 'w:pageBreakBefore ' ),
158
178
);
159
179
160
- $ nodes = $ xmlReader ->getElements ('w:pPr/* ' , $ domNode );
161
- foreach ($ nodes as $ node ) {
162
- if (!array_key_exists ($ node ->nodeName , $ mapping )) {
163
- continue ;
164
- }
165
- $ property = $ mapping [$ node ->nodeName ];
166
- switch ($ node ->nodeName ) {
167
-
168
- case 'w:ind ' :
169
- $ style ['indent ' ] = $ xmlReader ->getAttribute ('w:left ' , $ node );
170
- $ style ['hanging ' ] = $ xmlReader ->getAttribute ('w:hanging ' , $ node );
171
- break ;
172
-
173
- case 'w:spacing ' :
174
- $ style ['spaceAfter ' ] = $ xmlReader ->getAttribute ('w:after ' , $ node );
175
- $ style ['spaceBefore ' ] = $ xmlReader ->getAttribute ('w:before ' , $ node );
176
- // Commented. Need to adjust the number when return value is null
177
- // $style['spacing'] = $xmlReader->getAttribute('w:line', $node);
178
- break ;
179
-
180
- case 'w:keepNext ' :
181
- case 'w:keepLines ' :
182
- case 'w:pageBreakBefore ' :
183
- $ style [$ property ] = true ;
184
- break ;
185
-
186
- case 'w:widowControl ' :
187
- $ style [$ property ] = false ;
188
- break ;
189
-
190
- case 'w:pStyle ' :
191
- case 'w:jc ' :
192
- case 'w:basedOn ' :
193
- case 'w:next ' :
194
- $ style [$ property ] = $ xmlReader ->getAttribute ('w:val ' , $ node );
195
- break ;
196
- }
197
- }
198
-
199
- return $ style ;
180
+ return $ this ->readStyleDefs ($ xmlReader , $ styleNode , $ styleDefs );
200
181
}
201
182
202
183
/**
203
184
* Read w:rPr
204
185
*
205
186
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
206
187
* @param \DOMElement $domNode
207
- * @return array|null
188
+ * @return array
208
189
*/
209
190
protected function readFontStyle (XMLReader $ xmlReader , \DOMElement $ domNode )
210
191
{
@@ -219,62 +200,26 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode)
219
200
return null ;
220
201
}
221
202
222
- $ style = array ();
223
- $ mapping = array (
224
- 'w:rStyle ' => 'styleName ' ,
225
- 'w:b ' => 'bold ' , 'w:i ' => 'italic ' , 'w:color ' => 'color ' , 'w:u ' => 'underline ' ,
226
- 'w:strike ' => 'strikethrough ' , 'w:dstrike ' => 'doubleStrikethrough ' ,
227
- 'w:highlight ' => 'fgColor ' , 'w:sz ' => 'size ' ,
228
- 'w:rFonts ' => 'name ' , 'w:vertAlign ' => 'superScript ' ,
229
- 'w:smallCaps ' => 'smallCaps ' , 'w:caps ' => 'allCaps ' ,
203
+ $ styleNode = $ xmlReader ->getElement ('w:rPr ' , $ domNode );
204
+ $ styleDefs = array (
205
+ 'styleName ' => array (self ::READ_VALUE , 'w:rStyle ' ),
206
+ 'name ' => array (self ::READ_VALUE , 'w:rFonts ' , 'w:ascii ' ),
207
+ 'hint ' => array (self ::READ_VALUE , 'w:rFonts ' , 'w:hint ' ),
208
+ 'size ' => array (self ::READ_SIZE , 'w:sz ' ),
209
+ 'color ' => array (self ::READ_VALUE , 'w:color ' ),
210
+ 'underline ' => array (self ::READ_VALUE , 'w:u ' ),
211
+ 'bold ' => array (self ::READ_TRUE , 'w:b ' ),
212
+ 'italic ' => array (self ::READ_TRUE , 'w:i ' ),
213
+ 'strikethrough ' => array (self ::READ_TRUE , 'w:strike ' ),
214
+ 'doubleStrikethrough ' => array (self ::READ_TRUE , 'w:dstrike ' ),
215
+ 'smallCaps ' => array (self ::READ_TRUE , 'w:smallCaps ' ),
216
+ 'allCaps ' => array (self ::READ_TRUE , 'w:caps ' ),
217
+ 'superScript ' => array (self ::READ_EQUAL , 'w:vertAlign ' , 'w:val ' , 'superscript ' ),
218
+ 'subScript ' => array (self ::READ_EQUAL , 'w:vertAlign ' , 'w:val ' , 'subscript ' ),
219
+ 'fgColor ' => array (self ::READ_VALUE , 'w:highlight ' ),
230
220
);
231
221
232
- $ nodes = $ xmlReader ->getElements ('w:rPr/* ' , $ domNode );
233
- foreach ($ nodes as $ node ) {
234
- if (!array_key_exists ($ node ->nodeName , $ mapping )) {
235
- continue ;
236
- }
237
- $ property = $ mapping [$ node ->nodeName ];
238
- switch ($ node ->nodeName ) {
239
-
240
- case 'w:rFonts ' :
241
- $ style ['name ' ] = $ xmlReader ->getAttribute ('w:ascii ' , $ node );
242
- $ style ['hint ' ] = $ xmlReader ->getAttribute ('w:hint ' , $ node );
243
- break ;
244
-
245
- case 'w:b ' :
246
- case 'w:i ' :
247
- case 'w:strike ' :
248
- case 'w:dstrike ' :
249
- case 'w:smallCaps ' :
250
- case 'w:caps ' :
251
- $ style [$ property ] = true ;
252
- break ;
253
-
254
- case 'w:rStyle ' :
255
- case 'w:u ' :
256
- case 'w:highlight ' :
257
- case 'w:color ' :
258
- $ style [$ property ] = $ xmlReader ->getAttribute ('w:val ' , $ node );
259
- break ;
260
-
261
- case 'w:sz ' :
262
- $ style [$ property ] = $ xmlReader ->getAttribute ('w:val ' , $ node ) / 2 ;
263
- break ;
264
-
265
- case 'w:vertAlign ' :
266
- $ style [$ property ] = $ xmlReader ->getAttribute ('w:val ' , $ node );
267
- if ($ style [$ property ] == 'superscript ' ) {
268
- $ style ['superScript ' ] = true ;
269
- } else {
270
- $ style ['superScript ' ] = false ;
271
- $ style ['subScript ' ] = true ;
272
- }
273
- break ;
274
- }
275
- }
276
-
277
- return $ style ;
222
+ return $ this ->readStyleDefs ($ xmlReader , $ styleNode , $ styleDefs );
278
223
}
279
224
280
225
/**
@@ -295,42 +240,64 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode)
295
240
if ($ xmlReader ->elementExists ('w:tblPr/w:tblStyle ' , $ domNode )) {
296
241
$ style = $ xmlReader ->getAttribute ('w:val ' , $ domNode , 'w:tblPr/w:tblStyle ' );
297
242
} else {
298
- $ style = array ();
299
- $ mapping = array (
300
- 'w:tblCellMar ' => 'cellMargin ' ,
301
- 'w:tblBorders ' => 'border ' ,
302
- );
303
-
304
- $ nodes = $ xmlReader ->getElements ('w:tblPr/* ' , $ domNode );
305
- foreach ($ nodes as $ node ) {
306
- if (!array_key_exists ($ node ->nodeName , $ mapping )) {
307
- continue ;
308
- }
309
- // $property = $mapping[$node->nodeName];
310
- switch ($ node ->nodeName ) {
311
-
312
- case 'w:tblCellMar ' :
313
- foreach ($ margins as $ side ) {
314
- $ ucfSide = ucfirst ($ side );
315
- $ style ["cellMargin $ ucfSide " ] = $ xmlReader ->getAttribute ('w:w ' , $ node , "w: $ side " );
316
- }
317
- break ;
318
-
319
- case 'w:tblBorders ' :
320
- foreach ($ borders as $ side ) {
321
- $ ucfSide = ucfirst ($ side );
322
- $ style ["border {$ ucfSide }Size " ] = $ xmlReader ->getAttribute ('w:sz ' , $ node , "w: $ side " );
323
- $ style ["border {$ ucfSide }Color " ] = $ xmlReader ->getAttribute ('w:color ' , $ node , "w: $ side " );
324
- }
325
- break ;
326
- }
243
+ $ styleNode = $ xmlReader ->getElement ('w:tblPr ' , $ domNode );
244
+ // $styleDefs['styleName'] = array(self::READ_VALUE, 'w:tblStyle');
245
+ foreach ($ margins as $ side ) {
246
+ $ ucfSide = ucfirst ($ side );
247
+ $ styleDefs ["cellMargin $ ucfSide " ] = array (self ::READ_VALUE , "w:tblCellMar/w: $ side " , 'w:w ' );
327
248
}
249
+ foreach ($ borders as $ side ) {
250
+ $ ucfSide = ucfirst ($ side );
251
+ $ styleDefs ["border {$ ucfSide }Size " ] = array (self ::READ_VALUE , "w:tblBorders/w: $ side " , 'w:sz ' );
252
+ $ styleDefs ["border {$ ucfSide }Color " ] = array (self ::READ_VALUE , "w:tblBorders/w: $ side " , 'w:color ' );
253
+ }
254
+ $ style = $ this ->readStyleDefs ($ xmlReader , $ styleNode , $ styleDefs );
328
255
}
329
256
}
330
257
331
258
return $ style ;
332
259
}
333
260
261
+ /**
262
+ * Read style definition
263
+ *
264
+ * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
265
+ * @param \DOMElement $domNode
266
+ * @param array $styleDefs
267
+ * @return array
268
+ */
269
+ protected function readStyleDefs (XMLReader $ xmlReader , \DOMElement $ parentNode , $ styleDefs )
270
+ {
271
+ $ styles = array ();
272
+
273
+ foreach ($ styleDefs as $ styleProp => $ styleVal ) {
274
+ @list ($ method , $ element , $ attribute , $ expected ) = $ styleVal ;
275
+
276
+ if ($ xmlReader ->elementExists ($ element , $ parentNode )) {
277
+ $ node = $ xmlReader ->getElement ($ element , $ parentNode );
278
+
279
+ // Use w:val as default if no attribute assigned
280
+ $ attribute = ($ attribute === null ) ? 'w:val ' : $ attribute ;
281
+ $ attributeValue = $ xmlReader ->getAttribute ($ attribute , $ node );
282
+
283
+ // Assign style value based on conversion model
284
+ if ($ method == self ::READ_VALUE ) {
285
+ $ styles [$ styleProp ] = $ attributeValue ;
286
+ } elseif ($ method == self ::READ_SIZE ) {
287
+ $ styles [$ styleProp ] = $ attributeValue / 2 ;
288
+ } elseif ($ method == self ::READ_TRUE ) {
289
+ $ styles [$ styleProp ] = true ;
290
+ } elseif ($ method == self ::READ_FALSE ) {
291
+ $ styles [$ styleProp ] = false ;
292
+ } elseif ($ method == self ::READ_EQUAL && $ attributeValue == $ expected ) {
293
+ $ styles [$ styleProp ] = true ;
294
+ }
295
+ }
296
+ }
297
+
298
+ return $ styles ;
299
+ }
300
+
334
301
/**
335
302
* Returns the target of image, object, or link as stored in ::readMainRels
336
303
*
0 commit comments