Refactor reader
This commit is contained in:
parent
f7bee23f65
commit
69a3a0f4f2
|
|
@ -22,9 +22,22 @@ use PhpOffice\PhpWord\Shared\XMLReader;
|
|||
|
||||
/**
|
||||
* Abstract part reader
|
||||
*
|
||||
* This class is inherited by ODText reader
|
||||
*/
|
||||
abstract class AbstractPart
|
||||
{
|
||||
/**
|
||||
* Conversion method
|
||||
*
|
||||
* @const int
|
||||
*/
|
||||
const READ_VALUE = 'attributeValue'; // Read attribute value
|
||||
const READ_EQUAL = 'attributeEquals'; // Read `true` when attribute value equals specified value
|
||||
const READ_TRUE = 'attributeTrue'; // Read `true` when element exists
|
||||
const READ_FALSE = 'attributeFalse'; // Read `false` when element exists
|
||||
const READ_SIZE = 'attributeMultiplyByTwo'; // Read special attribute value for Font::$size
|
||||
|
||||
/**
|
||||
* Document file
|
||||
*
|
||||
|
|
@ -145,58 +158,26 @@ abstract class AbstractPart
|
|||
protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode)
|
||||
{
|
||||
if (!$xmlReader->elementExists('w:pPr', $domNode)) {
|
||||
return '';
|
||||
return null;
|
||||
}
|
||||
|
||||
$style = array();
|
||||
$mapping = array(
|
||||
'w:pStyle' => 'styleName',
|
||||
'w:ind' => 'indent', 'w:spacing' => 'spacing',
|
||||
'w:jc' => 'align', 'w:basedOn' => 'basedOn', 'w:next' => 'next',
|
||||
'w:widowControl' => 'widowControl', 'w:keepNext' => 'keepNext',
|
||||
'w:keepLines' => 'keepLines', 'w:pageBreakBefore' => 'pageBreakBefore',
|
||||
$styleNode = $xmlReader->getElement('w:pPr', $domNode);
|
||||
$styleDefs = array(
|
||||
'styleName' => array(self::READ_VALUE, 'w:pStyle'),
|
||||
'align' => array(self::READ_VALUE, 'w:jc'),
|
||||
'basedOn' => array(self::READ_VALUE, 'w:basedOn'),
|
||||
'next' => array(self::READ_VALUE, 'w:next'),
|
||||
'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'),
|
||||
'hanging' => array(self::READ_VALUE, 'w:ind', 'w:hanging'),
|
||||
'spaceAfter' => array(self::READ_VALUE, 'w:spacing', 'w:after'),
|
||||
'spaceBefore' => array(self::READ_VALUE, 'w:spacing', 'w:before'),
|
||||
'widowControl' => array(self::READ_FALSE, 'w:widowControl'),
|
||||
'keepNext' => array(self::READ_TRUE, 'w:keepNext'),
|
||||
'keepLines' => array(self::READ_TRUE, 'w:keepLines'),
|
||||
'pageBreakBefore' => array(self::READ_TRUE, 'w:pageBreakBefore'),
|
||||
);
|
||||
|
||||
$nodes = $xmlReader->getElements('w:pPr/*', $domNode);
|
||||
foreach ($nodes as $node) {
|
||||
if (!array_key_exists($node->nodeName, $mapping)) {
|
||||
continue;
|
||||
}
|
||||
$property = $mapping[$node->nodeName];
|
||||
switch ($node->nodeName) {
|
||||
|
||||
case 'w:ind':
|
||||
$style['indent'] = $xmlReader->getAttribute('w:left', $node);
|
||||
$style['hanging'] = $xmlReader->getAttribute('w:hanging', $node);
|
||||
break;
|
||||
|
||||
case 'w:spacing':
|
||||
$style['spaceAfter'] = $xmlReader->getAttribute('w:after', $node);
|
||||
$style['spaceBefore'] = $xmlReader->getAttribute('w:before', $node);
|
||||
// Commented. Need to adjust the number when return value is null
|
||||
// $style['spacing'] = $xmlReader->getAttribute('w:line', $node);
|
||||
break;
|
||||
|
||||
case 'w:keepNext':
|
||||
case 'w:keepLines':
|
||||
case 'w:pageBreakBefore':
|
||||
$style[$property] = true;
|
||||
break;
|
||||
|
||||
case 'w:widowControl':
|
||||
$style[$property] = false;
|
||||
break;
|
||||
|
||||
case 'w:pStyle':
|
||||
case 'w:jc':
|
||||
case 'w:basedOn':
|
||||
case 'w:next':
|
||||
$style[$property] = $xmlReader->getAttribute('w:val', $node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -204,7 +185,7 @@ abstract class AbstractPart
|
|||
*
|
||||
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
|
||||
* @param \DOMElement $domNode
|
||||
* @return array|null
|
||||
* @return array
|
||||
*/
|
||||
protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode)
|
||||
{
|
||||
|
|
@ -219,62 +200,26 @@ abstract class AbstractPart
|
|||
return null;
|
||||
}
|
||||
|
||||
$style = array();
|
||||
$mapping = array(
|
||||
'w:rStyle' => 'styleName',
|
||||
'w:b' => 'bold', 'w:i' => 'italic', 'w:color' => 'color', 'w:u' => 'underline',
|
||||
'w:strike' => 'strikethrough', 'w:dstrike' => 'doubleStrikethrough',
|
||||
'w:highlight' => 'fgColor', 'w:sz' => 'size',
|
||||
'w:rFonts' => 'name', 'w:vertAlign' => 'superScript',
|
||||
'w:smallCaps' => 'smallCaps', 'w:caps' => 'allCaps',
|
||||
$styleNode = $xmlReader->getElement('w:rPr', $domNode);
|
||||
$styleDefs = array(
|
||||
'styleName' => array(self::READ_VALUE, 'w:rStyle'),
|
||||
'name' => array(self::READ_VALUE, 'w:rFonts', 'w:ascii'),
|
||||
'hint' => array(self::READ_VALUE, 'w:rFonts', 'w:hint'),
|
||||
'size' => array(self::READ_SIZE, 'w:sz'),
|
||||
'color' => array(self::READ_VALUE, 'w:color'),
|
||||
'underline' => array(self::READ_VALUE, 'w:u'),
|
||||
'bold' => array(self::READ_TRUE, 'w:b'),
|
||||
'italic' => array(self::READ_TRUE, 'w:i'),
|
||||
'strikethrough' => array(self::READ_TRUE, 'w:strike'),
|
||||
'doubleStrikethrough' => array(self::READ_TRUE, 'w:dstrike'),
|
||||
'smallCaps' => array(self::READ_TRUE, 'w:smallCaps'),
|
||||
'allCaps' => array(self::READ_TRUE, 'w:caps'),
|
||||
'superScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'superscript'),
|
||||
'subScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'),
|
||||
'fgColor' => array(self::READ_VALUE, 'w:highlight'),
|
||||
);
|
||||
|
||||
$nodes = $xmlReader->getElements('w:rPr/*', $domNode);
|
||||
foreach ($nodes as $node) {
|
||||
if (!array_key_exists($node->nodeName, $mapping)) {
|
||||
continue;
|
||||
}
|
||||
$property = $mapping[$node->nodeName];
|
||||
switch ($node->nodeName) {
|
||||
|
||||
case 'w:rFonts':
|
||||
$style['name'] = $xmlReader->getAttribute('w:ascii', $node);
|
||||
$style['hint'] = $xmlReader->getAttribute('w:hint', $node);
|
||||
break;
|
||||
|
||||
case 'w:b':
|
||||
case 'w:i':
|
||||
case 'w:strike':
|
||||
case 'w:dstrike':
|
||||
case 'w:smallCaps':
|
||||
case 'w:caps':
|
||||
$style[$property] = true;
|
||||
break;
|
||||
|
||||
case 'w:rStyle':
|
||||
case 'w:u':
|
||||
case 'w:highlight':
|
||||
case 'w:color':
|
||||
$style[$property] = $xmlReader->getAttribute('w:val', $node);
|
||||
break;
|
||||
|
||||
case 'w:sz':
|
||||
$style[$property] = $xmlReader->getAttribute('w:val', $node) / 2;
|
||||
break;
|
||||
|
||||
case 'w:vertAlign':
|
||||
$style[$property] = $xmlReader->getAttribute('w:val', $node);
|
||||
if ($style[$property] == 'superscript') {
|
||||
$style['superScript'] = true;
|
||||
} else {
|
||||
$style['superScript'] = false;
|
||||
$style['subScript'] = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -295,42 +240,64 @@ abstract class AbstractPart
|
|||
if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) {
|
||||
$style = $xmlReader->getAttribute('w:val', $domNode, 'w:tblPr/w:tblStyle');
|
||||
} else {
|
||||
$style = array();
|
||||
$mapping = array(
|
||||
'w:tblCellMar' => 'cellMargin',
|
||||
'w:tblBorders' => 'border',
|
||||
);
|
||||
|
||||
$nodes = $xmlReader->getElements('w:tblPr/*', $domNode);
|
||||
foreach ($nodes as $node) {
|
||||
if (!array_key_exists($node->nodeName, $mapping)) {
|
||||
continue;
|
||||
}
|
||||
// $property = $mapping[$node->nodeName];
|
||||
switch ($node->nodeName) {
|
||||
|
||||
case 'w:tblCellMar':
|
||||
$styleNode = $xmlReader->getElement('w:tblPr', $domNode);
|
||||
// $styleDefs['styleName'] = array(self::READ_VALUE, 'w:tblStyle');
|
||||
foreach ($margins as $side) {
|
||||
$ucfSide = ucfirst($side);
|
||||
$style["cellMargin$ucfSide"] = $xmlReader->getAttribute('w:w', $node, "w:$side");
|
||||
$styleDefs["cellMargin$ucfSide"] = array(self::READ_VALUE, "w:tblCellMar/w:$side", 'w:w');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'w:tblBorders':
|
||||
foreach ($borders as $side) {
|
||||
$ucfSide = ucfirst($side);
|
||||
$style["border{$ucfSide}Size"] = $xmlReader->getAttribute('w:sz', $node, "w:$side");
|
||||
$style["border{$ucfSide}Color"] = $xmlReader->getAttribute('w:color', $node, "w:$side");
|
||||
}
|
||||
break;
|
||||
}
|
||||
$styleDefs["border{$ucfSide}Size"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:sz');
|
||||
$styleDefs["border{$ucfSide}Color"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:color');
|
||||
}
|
||||
$style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read style definition
|
||||
*
|
||||
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
|
||||
* @param \DOMElement $domNode
|
||||
* @param array $styleDefs
|
||||
* @return array
|
||||
*/
|
||||
protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode, $styleDefs)
|
||||
{
|
||||
$styles = array();
|
||||
|
||||
foreach ($styleDefs as $styleProp => $styleVal) {
|
||||
@list($method, $element, $attribute, $expected) = $styleVal;
|
||||
|
||||
if ($xmlReader->elementExists($element, $parentNode)) {
|
||||
$node = $xmlReader->getElement($element, $parentNode);
|
||||
|
||||
// Use w:val as default if no attribute assigned
|
||||
$attribute = ($attribute === null) ? 'w:val' : $attribute;
|
||||
$attributeValue = $xmlReader->getAttribute($attribute, $node);
|
||||
|
||||
// Assign style value based on conversion model
|
||||
if ($method == self::READ_VALUE) {
|
||||
$styles[$styleProp] = $attributeValue;
|
||||
} elseif ($method == self::READ_SIZE) {
|
||||
$styles[$styleProp] = $attributeValue / 2;
|
||||
} elseif ($method == self::READ_TRUE) {
|
||||
$styles[$styleProp] = true;
|
||||
} elseif ($method == self::READ_FALSE) {
|
||||
$styles[$styleProp] = false;
|
||||
} elseif ($method == self::READ_EQUAL && $attributeValue == $expected) {
|
||||
$styles[$styleProp] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target of image, object, or link as stored in ::readMainRels
|
||||
*
|
||||
|
|
|
|||
|
|
@ -56,10 +56,8 @@ class Document extends AbstractPart
|
|||
if (!is_null($settingsNode)) {
|
||||
$settings = $this->readSectionStyle($xmlReader, $settingsNode);
|
||||
$section->setSettings($settings);
|
||||
if (!is_null($settings)) {
|
||||
$this->readHeaderFooter($settings, $section);
|
||||
}
|
||||
}
|
||||
$section = $phpWord->addSection();
|
||||
}
|
||||
break;
|
||||
|
|
@ -71,9 +69,7 @@ class Document extends AbstractPart
|
|||
case 'w:sectPr': // Last section
|
||||
$settings = $this->readSectionStyle($xmlReader, $node);
|
||||
$section->setSettings($settings);
|
||||
if (!is_null($settings)) {
|
||||
$this->readHeaderFooter($settings, $section);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -273,61 +269,41 @@ class Document extends AbstractPart
|
|||
*
|
||||
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
|
||||
* @param \DOMElement $domNode
|
||||
* @return array|null
|
||||
* @return array
|
||||
*/
|
||||
private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode)
|
||||
{
|
||||
$ret = null;
|
||||
$mapping = array(
|
||||
'w:type' => 'breakType', 'w:pgSz' => 'pageSize',
|
||||
'w:pgMar' => 'pageMargin', 'w:cols' => 'columns',
|
||||
'w:headerReference' => 'header', 'w:footerReference' => 'footer',
|
||||
$styleDefs = array(
|
||||
'breakType' => array(self::READ_VALUE, 'w:type'),
|
||||
'pageSizeW' => array(self::READ_VALUE, 'w:pgSz', 'w:w'),
|
||||
'pageSizeH' => array(self::READ_VALUE, 'w:pgSz', 'w:h'),
|
||||
'orientation' => array(self::READ_VALUE, 'w:pgSz', 'w:orient'),
|
||||
'colsNum' => array(self::READ_VALUE, 'w:cols', 'w:num'),
|
||||
'colsSpace' => array(self::READ_VALUE, 'w:cols', 'w:space'),
|
||||
'topMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:top'),
|
||||
'leftMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:left'),
|
||||
'bottomMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'),
|
||||
'rightMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:right'),
|
||||
'headerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:header'),
|
||||
'footerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:footer'),
|
||||
'gutter' => array(self::READ_VALUE, 'w:pgMar', 'w:gutter'),
|
||||
);
|
||||
$styles = $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
|
||||
|
||||
// Header and footer
|
||||
// @todo Cleanup this part
|
||||
$nodes = $xmlReader->getElements('*', $domNode);
|
||||
foreach ($nodes as $node) {
|
||||
if (!array_key_exists($node->nodeName, $mapping)) {
|
||||
continue;
|
||||
}
|
||||
$property = $mapping[$node->nodeName];
|
||||
switch ($node->nodeName) {
|
||||
|
||||
case 'w:type':
|
||||
$ret['breakType'] = $xmlReader->getAttribute('w:val', $node);
|
||||
break;
|
||||
|
||||
case 'w:pgSz':
|
||||
$ret['pageSizeW'] = $xmlReader->getAttribute('w:w', $node);
|
||||
$ret['pageSizeH'] = $xmlReader->getAttribute('w:h', $node);
|
||||
$ret['orientation'] = $xmlReader->getAttribute('w:orient', $node);
|
||||
break;
|
||||
|
||||
case 'w:pgMar':
|
||||
$ret['topMargin'] = $xmlReader->getAttribute('w:top', $node);
|
||||
$ret['leftMargin'] = $xmlReader->getAttribute('w:left', $node);
|
||||
$ret['bottomMargin'] = $xmlReader->getAttribute('w:bottom', $node);
|
||||
$ret['rightMargin'] = $xmlReader->getAttribute('w:right', $node);
|
||||
$ret['headerHeight'] = $xmlReader->getAttribute('w:header', $node);
|
||||
$ret['footerHeight'] = $xmlReader->getAttribute('w:footer', $node);
|
||||
$ret['gutter'] = $xmlReader->getAttribute('w:gutter', $node);
|
||||
break;
|
||||
|
||||
case 'w:cols':
|
||||
$ret['colsNum'] = $xmlReader->getAttribute('w:num', $node);
|
||||
$ret['colsSpace'] = $xmlReader->getAttribute('w:space', $node);
|
||||
break;
|
||||
|
||||
case 'w:headerReference':
|
||||
case 'w:footerReference':
|
||||
if ($node->nodeName == 'w:headerReference' || $node->nodeName == 'w:footerReference') {
|
||||
$id = $xmlReader->getAttribute('r:id', $node);
|
||||
$ret['hf'][$id] = array(
|
||||
'method' => $property,
|
||||
$styles['hf'][$id] = array(
|
||||
'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)),
|
||||
'type' => $xmlReader->getAttribute('w:type', $node),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
return $styles;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -335,33 +311,18 @@ class Document extends AbstractPart
|
|||
*
|
||||
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
|
||||
* @param \DOMElement $domNode
|
||||
* @return array|null
|
||||
* @return array
|
||||
*/
|
||||
private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode)
|
||||
{
|
||||
$style = null;
|
||||
$mapping = array(
|
||||
'w:shd' => 'bgColor',
|
||||
'w:vAlign' => 'valign', 'w:textDirection' => 'textDirection',
|
||||
'w:gridSpan' => 'gridSpan', 'w:vMerge' => 'vMerge',
|
||||
$styleDefs = array(
|
||||
'valign' => array(self::READ_VALUE, 'w:vAlign'),
|
||||
'textDirection' => array(self::READ_VALUE, 'w:textDirection'),
|
||||
'gridSpan' => array(self::READ_VALUE, 'w:gridSpan'),
|
||||
'vMerge' => array(self::READ_VALUE, 'w:vMerge'),
|
||||
'bgColor' => array(self::READ_VALUE, 'w:shd/w:fill'),
|
||||
);
|
||||
$nodes = $xmlReader->getElements('*', $domNode);
|
||||
foreach ($nodes as $node) {
|
||||
if (!array_key_exists($node->nodeName, $mapping)) {
|
||||
continue;
|
||||
}
|
||||
$property = $mapping[$node->nodeName];
|
||||
switch ($node->nodeName) {
|
||||
case 'w:shd':
|
||||
$style['bgColor'] = $xmlReader->getAttribute('w:fill', $node);
|
||||
break;
|
||||
|
||||
default:
|
||||
$style[$property] = $xmlReader->getAttribute('w:val', $node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $style;
|
||||
return $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue