Skip to content

Commit 108c1cd

Browse files
committed
Html parser (addHtml) - support attributes start, type in ordered list <ol>
1 parent ca5f081 commit 108c1cd

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

src/PhpWord/Shared/Html.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,31 @@ protected static function parseList($node, $element, &$styles, &$data)
447447
} else {
448448
$data['listdepth'] = 0;
449449
$styles['list'] = 'listStyle_' . self::$listIndex++;
450-
$element->getPhpWord()->addNumberingStyle($styles['list'], self::getListStyle($isOrderedList));
450+
$style = $element->getPhpWord()->addNumberingStyle($styles['list'], self::getListStyle($isOrderedList));
451+
452+
// extract attributes start & type e.g. <ol type="A" start="3">
453+
$start = 0;
454+
$type = '';
455+
foreach ($node->attributes as $attribute) {
456+
switch ($attribute->name) {
457+
case 'start':
458+
$start = (int) $attribute->value;
459+
break;
460+
case 'type':
461+
$type = $attribute->value;
462+
break;
463+
}
464+
}
465+
466+
$levels = $style->getLevels();
467+
/** @var \PhpOffice\PhpWord\Style\NumberingLevel */
468+
$level = $levels[0];
469+
if($start > 0){
470+
$level->setStart($start);
471+
}
472+
if($type && !!($type = self::mapListType($type))){
473+
$level->setFormat($type);
474+
}
451475
}
452476
if ($node->parentNode->nodeName === 'li') {
453477
return $element->getParent();
@@ -818,6 +842,28 @@ protected static function mapAlign($cssAlignment)
818842
}
819843
}
820844

845+
/**
846+
* Map list style for ordered list
847+
*
848+
* @param string $cssListType
849+
*/
850+
protected static function mapListType($cssListType)
851+
{
852+
switch ($cssListType) {
853+
case 'a':
854+
return NumberFormat::LOWER_LETTER; // a, b, c, ..
855+
case 'A':
856+
return NumberFormat::UPPER_LETTER; // A, B, C, ..
857+
case 'i':
858+
return NumberFormat::LOWER_ROMAN; // i, ii, iii, iv, ..
859+
case 'I':
860+
return NumberFormat::UPPER_ROMAN; // I, II, III, IV, ..
861+
case '1':
862+
default:
863+
return NumberFormat::DECIMAL; // 1, 2, 3, ..
864+
}
865+
}
866+
821867
/**
822868
* Parse line break
823869
*

tests/PhpWord/Shared/HtmlTest.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,4 +784,64 @@ public function testParseHorizRule()
784784
$this->assertEquals(240, $doc->getElement($xpath)->getAttribute('w:line'));
785785
}
786786

787+
/**
788+
* Parse ordered list start & numbering style
789+
*/
790+
public function testParseOrderedList()
791+
{
792+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
793+
$section = $phpWord->addSection();
794+
795+
// borders & backgrounds are here just for better visual comparison
796+
$html = <<<HTML
797+
<ol>
798+
<li>standard ordered list line 1</li>
799+
<li>standard ordered list line 2</li>
800+
</ol>
801+
802+
<ol start="5" type="A">
803+
<li>ordered list alphabetical, <span style="background-color: #EEEEEE; color: #FF0000;">line 5 => E</span></li>
804+
<li>ordered list alphabetical, <span style="background-color: #EEEEEE; color: #FF0000;">line 6 => F</span></li>
805+
</ol>
806+
807+
<ol start="3" type="i">
808+
<li>ordered list roman lower, line <b>3 => iii</b></li>
809+
<li>ordered list roman lower, line <b>4 => iv</b></li>
810+
</ol>
811+
812+
HTML;
813+
814+
Html::addHtml($section, $html);
815+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
816+
817+
// compare numbering file
818+
$xmlFile = 'word/numbering.xml';
819+
820+
// default - decimal start = 1
821+
$xpath = '/w:numbering/w:abstractNum[1]/w:lvl[1]/w:start';
822+
$this->assertTrue($doc->elementExists($xpath, $xmlFile));
823+
$this->assertEquals('1', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
824+
825+
$xpath = '/w:numbering/w:abstractNum[1]/w:lvl[1]/w:numFmt';
826+
$this->assertTrue($doc->elementExists($xpath, $xmlFile));
827+
$this->assertEquals('decimal', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
828+
829+
// second list - start = 5, type A = upperLetter
830+
$xpath = '/w:numbering/w:abstractNum[2]/w:lvl[1]/w:start';
831+
$this->assertTrue($doc->elementExists($xpath, $xmlFile));
832+
$this->assertEquals('5', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
833+
834+
$xpath = '/w:numbering/w:abstractNum[2]/w:lvl[1]/w:numFmt';
835+
$this->assertTrue($doc->elementExists($xpath, $xmlFile));
836+
$this->assertEquals('upperLetter', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
837+
838+
// third list - start = 3, type i = lowerRoman
839+
$xpath = '/w:numbering/w:abstractNum[3]/w:lvl[1]/w:start';
840+
$this->assertTrue($doc->elementExists($xpath, $xmlFile));
841+
$this->assertEquals('3', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
842+
843+
$xpath = '/w:numbering/w:abstractNum[3]/w:lvl[1]/w:numFmt';
844+
$this->assertTrue($doc->elementExists($xpath, $xmlFile));
845+
$this->assertEquals('lowerRoman', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
846+
}
787847
}

0 commit comments

Comments
 (0)