php [Php - Phpoffice Override]覆盖PHPOffice\PHPWord类以从HTML代码生成docx文件。当orde时,这个生成正确的数字

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php [Php - Phpoffice Override]覆盖PHPOffice\PHPWord类以从HTML代码生成docx文件。当orde时,这个生成正确的数字相关的知识,希望对你有一定的参考价值。

<?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-2016 PHPWord contributors
 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
 */

namespace Application\PhpOffice\PhpWord\Shared;

use PhpOffice\PhpWord\Shared\Html;
use PhpOffice\PhpWord\Element\AbstractContainer;
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Row;

/**
 * Common Html functions
 *
 * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
 */
class ErpHtml extends Html
{  
  //public static $phpWord=null;

    /**
    *  Hold styles from parent elements,
    *  allowing child elements inherit attributes.
    *  So if you whant your table row have bold font
    *  you can do:
    *     <tr style="font-weight: bold; ">
    *  instead of
    *     <tr>
    *       <td>
    *           <p style="font-weight: bold;">
    *       ...
    *
    *  Before DOM element children are processed,
    *  the parent DOM element styles are added to the stack.
    *  The styles for each child element is composed by
    *  its styles plus the parent styles.
    */
    public static $stylesStack=null;
    
    private static $rowSpanLimiter = 0;
    private static $rowSpanColFollower = 0;
    
    private static $rowCounter = 0;
    
    private static $cellCounter = 0;
    
    private static $listResetStyle = 0;
    
    private static $nodeStack = array();
    
    /**
     * Add HTML parts.
     *
     * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter
     *
     * @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
     * @return void
     */
    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.
         */

        // Preprocess: remove all line ends, decode HTML entity,
        // fix ampersand and angle brackets and add body tag for HTML fragments
        $html = str_replace(array("\n", "\r"), '', $html);
        $html = str_replace(array('&lt;', '&gt;', '&amp;'), array('_lt_', '_gt_', '_amp_'), $html);
        $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8');
        $html = str_replace('&', '&amp;', $html);
        $html = str_replace(array('_lt_', '_gt_', '_amp_'), array('&lt;', '&gt;', '&amp;'), $html);

        if (false === $fullHTML) {
            $html = '<body>' . $html . '</body>';
        }

        // Load DOM
        $dom = new \DOMDocument();
        $dom->preserveWhiteSpace = true;
        $dom->loadXML($html);
        $node = $dom->getElementsByTagName('body');

        //self::$phpWord = $element->getPhpWord();
        self::$stylesStack = array();

        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 $styles is supplied, the inline style attributes are added to the already existing style
     * @return array
     */
    protected static function parseInlineStyle($node, $styles = array())
    {            
        if (XML_ELEMENT_NODE == $node->nodeType) {            
            $stylesStr = $node->getAttribute('style');
            $styles = self::parseStyle($node, $stylesStr, $styles);
        }
        else
        {
            // Just to balance the stack.
            // (make number of pushs = number of pops)
            self::pushStyles(array());
        } 

        return $styles;
    }

    /**
     * Parse a node and add a corresponding element to the parent element.
     *
     * @param \DOMNode $node node to parse
     * @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
     * @return void
     */
    protected static function parseNode($node, $element, $styles = array(), $data = array())
    {
        // Populate styles array
        $styleTypes = array('font', 'paragraph', 'list', 'table', 'row', 'cell'); //@change
        foreach ($styleTypes as $styleType) {
            if (!isset($styles[$styleType])) {
                $styles[$styleType] = array();
            }
        }

        // Node mapping table
        $nodes = array(
                              // $method        $node   $element    $styles     $data   $argument1      $argument2
            'p'         => array('Paragraph',   $node,  $element,   $styles,    null,   null,           null),
            'h1'        => array('Heading',     $node,   $element,   $styles,    null,   'Heading1',     null),
            'h2'        => array('Heading',     $node,   $element,   $styles,    null,   'Heading2',     null),
            'h3'        => array('Heading',     $node,   $element,   $styles,    null,   'Heading3',     null),
            'h4'        => array('Heading',     $node,   $element,   $styles,    null,   'Heading4',     null),
            'h5'        => array('Heading',     $node,   $element,   $styles,    null,   'Heading5',     null),
            'h6'        => array('Heading',     $node,   $element,   $styles,    null,   'Heading6',     null),
            '#text'     => array('Text',        $node,  $element,   $styles,    null,    null,          null),
            'span'      => array('Span',        $node,  null,       $styles,    null,    null,          null), //to catch inline span style changes
            '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),
            'thead'     => array('Table',       $node,  $element,   $styles,    null,   'skipTbody',    true), //added to catch tbody in html.
            'tbody'     => array('Table',       $node,  $element,   $styles,    null,   'skipTbody',    true), //added to catch tbody in html.
            'tr'        => array('Table',       $node,  $element,   $styles,    null,   'addRow',       true),
            'td'        => array('Table',       $node,  $element,   $styles,    null,   'addCell',      true),
            'th'        => array('Table',       $node,  $element,   $styles,    null,   'addCell',      true),
            'ul'        => array('List',        $node,  $element,   $styles,    $data,  3,              null),
            'ol'        => array('List',        $node,  $element,   $styles,    $data,  7,              null),
            'li'        => array('ListItem',    $node,  $element,   $styles,    $data,  null,           null),
        );

        $newElement = null;
        $keys = array('node', 'element', 'styles', 'data', 'argument1', 'argument2');

        if (isset($nodes[$node->nodeName])) {
            if($node->nodeName != '#text')
            array_push(self::$nodeStack, $node->nodeName);
            
            // 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('Application\PhpOffice\PhpWord\Shared\ErpHtml', $method), $arguments);

            // Retrieve back variables from arguments
            foreach ($keys as $key) {
                if (array_key_exists($key, $arguments)) {
                    $$key = $arguments[$key];
                }
            }
        }
        else
        {
            // Just to balance the stack.
            // Number of pushs = number of pops.
            self::pushStyles(array());
        }

        if ($newElement === null) {
            $newElement = $element;
        }

        self::parseChildNodes($node, $newElement, $styles, $data);

        // After the parent element be processed, 
        // its styles are removed from stack.
        self::popStyles();        
    }

    /**
     * Parse child nodes.
     *
     * @param \DOMNode $node
     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
     * @param array $styles
     * @param array $data
     * @return void
     */
    private static function parseChildNodes($node, $element, $styles, $data)
    {
        if(!in_array(end(self::$nodeStack), array('ol', 'ul', 'li', 'table', 'tbody', 'tr', 'td', 'th')))
            self::$listResetStyle = 0;
        
        if ($node->nodeName != 'li') {
            $cNodes = $node->childNodes;
            if (count($cNodes) > 0) {
                foreach ($cNodes as $cNode) {                    
                    // Added to get tables to work                    
                    $htmlContainers = array(
                        'tbody',
                        'tr',
                        'td',
                        'th'
                    );
                    if (in_array( $cNode->nodeName, $htmlContainers ) ) {                        
                        self::parseNode($cNode, $element, $styles, $data);
                    }                              
                    // All other containers as defined in AbstractContainer
                    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)
    {
        $elementStyles = self::parseInlineStyle($node, $styles['paragraph']);
        $text = str_replace(array("<br />", "<br >", "<br>", "<br/>"), "\r\n", $node->nodeValue);
        $newElement = $element->addText($text, $elementStyles, $elementStyles);
//        $newElement = $element->addTextRun($elementStyles);

        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($node, $element, &$styles, $argument1)
    {
        $elementStyles = $argument1;        
        $textSizes = array("Heading1" => 18, "Heading2" => 16, "Heading3" => 14, "Heading4" => 12, "Heading5" => 10, "Heading6" => 8);        
        $newElement = $element->addText($node->nodeValue, array('size' => $textSizes, 'bold' => true), array("spaceAfter" => 300));
        
//        $newElement = $element->addTextRun($elementStyles);

        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)
    {
        $elementStyles = self::parseInlineStyle($node, $styles['font']);

        $textStyles = self::getInheritedTextStyles();
        $paragraphStyles = self::getInheritedParagraphStyles();
        
        // Commented as source of bug #257. `method_exists` doesn't seems to work properly in this case.
        // @todo Find better error checking for this one
        // if (method_exists($element, 'addText')) {
            $element->addText($node->nodeValue, $textStyles, $paragraphStyles);
        // }

        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)
    {     
        switch ($argument1) {
            case 'addTable':                        
                $elementStyles = self::parseInlineStyle($node, $styles['paragraph']);
                $elementStyles["cellMargin"] = 100;
                $newElement = $element->addTable($elementStyles);
                break;
            case 'skipTbody':                        
                $newElement = $element;
                break;
            case 'addRow':
              
                // Increase to know that we start new row
                self::$rowCounter++;
              
                // Reset to start counting cells from new row
                self::$cellCounter = 0;
                
                $elementStyles = self::parseInlineStyle($node, $styles['row']);
                $newElement = $element->addRow(null, $elementStyles);
                break;
            case 'addCell':               
                $elementStyles = self::parseInlineStyle($node, $styles['cell']);
                
                ++self::$cellCounter;
                
                $colspan = $node->getAttribute('colspan');        
                if (!empty($colspan)) {
                    $elementStyles['gridSpan'] = $colspan-0; 
                    self::$cellCounter =+ $colspan;
                }
                
                /**
                 * ROWSPAN PROCEDURE
                 */
                $rowspan = $node->getAttribute('rowspan');
                if (!empty($rowspan)) {
                  
                  // Set how many rows we need to affect with
                  self::$rowSpanLimiter = (int) $rowspan-1;
                  
                  // Set current number of column to affect rowspan to correct column further
                  self::$rowSpanColFollower = self::$cellCounter;
                  
                  // If this is a first rowspan than correct value for VMerge key is "restart"
                  $elementStyles['vMerge'] = "restart";
                } 
                
                // Check if its current cell number equals number of the previous cell with rowspan and if rowspan is still neccesery
                else if(self::$rowSpanColFollower == self::$cellCounter && self::$rowSpanLimiter > 0) {
                   $elementStyles['vMerge'] = "continue";
                   --self::$rowSpanLimiter;
                }
                
                // Global variable valign
                $elementStyles['vAlign'] = "center";
                $width = isset($elementStyles['width']) ? $elementStyles['width'] : 1750;
                unset($elementStyles["width"]);
                $newElement = $element->addCell($width, $elementStyles);
                break;
        }

        // $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;
    }

    private static function parseRow($node, $element, &$styles, $argument1)
    {
        $elementStyles = self::parseInlineStyle($node, $styles['row']);

        $newElement = $element->addRow(null, $elementStyles);

        return $newElement;
    }


    private static function parseCell($node, $element, &$styles, $argument1)
    {        
        $elementStyles = self::parseInlineStyle($node, $styles['cell']);

        $colspan = $node->getAttribute('colspan');        
        if (!empty($colspan))
            $elementStyles['gridSpan'] = $colspan-0;        

        $newElement = $element->addCell(null, $elementStyles);
        return $newElement;
    }

    /**
     * Parse list node
     *
     * @param \DOMNode $node
     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
     * @param array &$styles
     * @param array &$data
     * @param string $argument1 List type
     * @return null
     */
    private static function parseList($node, $element, &$styles, &$data, $argument1)
    {       
      if (isset($data['listdepth'])) {
          $data['listdepth']++;
      } else {
          $data['listdepth'] = 0;
          if($argument1 == 7 && self::$listResetStyle == 0) {
        
            $style = array( "listType" => $argument1, "type" => "hybridMultilevel");
            $levels = array(
              0 => '1, decimal, %1., left, 720, 720, 360, , default',
              1 => '1, lowerLetter, %2., left, 1440, 1440, 360, , ',
              2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',
              3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',
              4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',
              5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',
              6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',
              7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',
              8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',
            );
            $properties = array('start', 'format', 'text', 'alignment', 'tabPos', 'left', 'hanging', 'font', 'hint');   
            foreach ($levels as $key => $value) {
              $level = array();
              $levelProperties = explode(', ', $value);
              $level['level'] = $key;
              for ($i = 0; $i < count($properties); $i++) {
                  $property = $properties[$i];
                  $level[$property] = $levelProperties[$i];
              }
              $style['levels'][$key] = $level;
            }        
        
            self::$listResetStyle = "list".rand();
            $element->getPhpWord()->addNumberingStyle(self::$listResetStyle, $style);
          }
      }
      $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']);
            $element->addListItem($text, $data['listdepth'], $styles['font'], self::$listResetStyle, $styles['paragraph']);
        }

        return null;
    }

    /**
     * Parse style
     *
     * @param \DOMAttr $attribute
     * @param array $styles
     * @return array
     */
    private static function parseStyle($node, $stylesStr, $styles)
    {
        // Parses element styles.
        $newStyles = array();

        if (!empty($stylesStr))
        {
            $properties = explode(';', trim($stylesStr, " \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':
                                $newStyles['underline'] = 'single';
                                break;
                            case 'line-through':
                                $newStyles['strikethrough'] = true;
                                break;
                        }
                        break;                
                    case 'text-align':
                        $newStyles['alignment'] = $cValue; // todo: any mapping?
                        break;
                    case 'color':
                        $newStyles['color'] = trim($cValue, "#");
                        break;
                    case 'background-color':
                        $newStyles['bgColor'] = trim($cValue, "#");
                        break;
                    case 'font-weight':
                        if ($cValue=='bold')
                            $newStyles['bold'] = true;
                        break;                    
                    case 'font-size':
                        $newStyles['size'] = intval($cValue);
                        break;                    
                    case 'width':
                        $newStyles = self::parseWidth($newStyles, $cValue);
                        break;
                    case 'border-width':
                        $newStyles = self::parseBorderStyle($newStyles, $cValue);
                        break;
                    case 'border-color':
                        $newStyles = self::parseBorderColor($newStyles, $cValue);
                        break;
                    case 'border':
                        $newStyles = self::parseBorder($newStyles, $cValue);
                        break;  
                    case 'vertical-align':
                        $newStyles['vAlign'] = $cValue;
                        break;
                    case 'horizontal-align':
                    case 'align':
                        $newStyles['align'] = $cValue;
                        break;
                }
            }
        }
        
        // Add styles to stack.
        self::pushStyles($newStyles);
        // Inherit parent styles (including itself).
        $inheritedStyles = self::getInheritedStyles($node->nodeName);

        // Override default styles with the inherited ones.
        $styles = array_merge($styles, $inheritedStyles); 
        /* DEBUG
        if ($node->nodeName=='th')
        {
            echo '<pre>';
            print_r(self::$stylesStack);
            print_r($styles);
            //print_r($elementStyles);
            echo '</pre>';
        }
        */

        return $styles;
    }

    /**
    *  Parses the "width" style attribute, adding to styles
    *  array the corresponding PHPWORD attributes.
    */
    public static function parseWidth($styles, $cValue)
    {
        if (preg_match('/([0-9]+)px/', $cValue, $matches))
        {
            $styles['width'] = $matches[1];
            $styles['unit'] = 'dxa';
        }
        else if (preg_match('/([0-9]+)%/', $cValue, $matches))
        {
            $styles['width'] = $matches[1]*50;
            $styles['unit'] = 'pct';
        }
        else if (preg_match('/([0-9]+)/', $cValue, $matches))
        {
            $styles['width'] = $matches[1];
            $styles['unit'] = 'auto';
        }

        $styles['alignment'] = \PhpOffice\PhpWord\SimpleType\JcTable::START;

        return $styles;
    }

    /**
    *  Parses the "border-width" style attribute, adding to styles
    *  array the corresponding PHPWORD attributes.
    */
    public static function parseBorderWidth($styles, $cValue)
    {
        // border-width: 2px;
        if (preg_match('/([0-9]+)px/', $cValue, $matches))
            $styles['borderSize'] = $matches[1];

        return $styles;
    }

    /**
    *  Parses the "border-color" style attribute, adding to styles
    *  array the corresponding PHPWORD attributes.
    */
    public static function parseBorderColor($styles, $cValue)
    {
        // border-color: #FFAACC;
        $styles['borderColor'] = $cValue;

        return $styles;
    }    

    /**
    *  Parses the "border" style attribute, adding to styles
    *  array the corresponding PHPWORD attributes.
    */
    public static function parseBorder($styles, $cValue)
    {
        if (preg_match('/([0-9]+)px\s+solid\s+(\#[a-fA-F0-9]+)+/', $cValue, $matches))
        {
            $styles['borderSize'] = $matches[1];
            $styles['borderColor'] = $matches[2];
        }
        
        return $styles;
    }

    /**
    *  Return the inherited styles for text elements,
    *  considering current stack state.
    */
    public static function getInheritedTextStyles()
    {
        return self::getInheritedStyles('#text');
    }

    /**
    *  Return the inherited styles for paragraph elements,
    *  considering current stack state.
    */
    public static function getInheritedParagraphStyles()
    {
        return self::getInheritedStyles('p');
    }

    /**
    *  Return the inherited styles for a given nodeType,
    *  considering current stack state.
    */
    public static function  getInheritedStyles($nodeType)
    {
        $textStyles = array('color', 'bold', 'italic', 'type', 'size');
        $paragraphStyles = array('color', 'bold', 'italic', 'alignment', 'vAlign', 'size');

        // List of phpword styles relevant for each element types.
        $stylesMapping = array(
            'p'         => $paragraphStyles,
            'h1'        => $textStyles,
            'h2'        => $textStyles,
            'h3'        => $textStyles,
            'h4'        => $textStyles,
            'h5'        => $textStyles,
            'h6'        => $textStyles,
            '#text'     => $textStyles,
            'strong'    => $textStyles,
            'em'        => $textStyles,
            'sup'       => $textStyles,
            'sub'       => $textStyles,
            'table'     => array('width', 'borderSize', 'borderColor', 'unit', 'align', 'cellMargin', 'size'),
            'tr'        => array('bgColor', 'alignment', 'color'),
            'td'        => array('bgColor', 'alignment', 'color', 'vAlign', 'width', 'size'),
            'th'        => array('bgColor', 'alignment', 'color', 'vAlign', 'width'),
            'ul'        => $textStyles,
            'ol'        => $textStyles,
            'li'        => $textStyles,
        );

        $result = array();

        if (isset($stylesMapping[$nodeType]))
        {
            $nodeStyles = $stylesMapping[$nodeType];

            // Loop trough styles stack applying styles in
            // the right order.
            foreach (self::$stylesStack as $styles)
            {
                // Loop trough all styles applying only the relevants for
                // that node type.
                foreach ($styles as $name => $value)
                {
                    if (in_array($name, $nodeStyles))
                    {
                        $result[$name] = $value;
                    }
                }
            }
        }

        return $result;
    }


    /**
    *  Add the parent styles to stack, allowing
    *  children elements inherit from.
    */
    public static function pushStyles($styles)
    {
        self::$stylesStack[] = $styles;
    }

    /**
    *  Remove parent styles at end of recursion.
    */
    public static function popStyles()
    {
        array_pop(self::$stylesStack);
    }
}

以上是关于php [Php - Phpoffice Override]覆盖PHPOffice\PHPWord类以从HTML代码生成docx文件。当orde时,这个生成正确的数字的主要内容,如果未能解决你的问题,请参考以下文章

Laravel引入phpoffice/phpword替换Word文件内容

PHP简单操作Excel

#yyds干货盘点#Hyperf结合PhpOffice/PhpSpreadsheet实现Excel&CSV文件导出导入

用PHP读取ExcelCSV文件

php Nette - filtrnaformulářovémprvku

word文档转html格式在线预览,使用了phpoffice,pydocx,java POI各方案,最终用unoconv解决