Search code examples
phpxmlms-wordphpword

How to copy styles from generated file to target file


How to copy styles and numbering from generated file to target file Generated file image. In generated file bullet points are working fine when merge this to the target file getting issue Target file. The target file was copy of tempalte and a empty file. I assumed due to no numbering.xml it does not showing the bullets as bullets if that is true how can i add numbering to the target file.

generate.php

if(!empty($newresult['header']) && !empty($result['snapshot']))
                {
                    \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
                    $phpWord = new \PhpOffice\PhpWord\PhpWord();
                    $section = $phpWord->addSection();
                    
                    if(!empty($result['snapshot']))
                    {
                        $decoded = json_decode($result['snapshot'], true);
                        for($i = sizeof($decoded['blocks']) - 1; $i>= 0; $i--){
                            if($decoded['blocks'][$i]['text'] != '')
                                break;
                            else{
                                array_pop($decoded['blocks']);
                            }
                            
                        }
                        makeWordStrings($section, json_decode($newresult['snapshot'], true), $demographics, $decoded, $tabSize, 0);
                    } 
                    
                    $newfilename = $filename;
                    if(mysqli_num_rows($query) > 1){
                        if($result['file_part_number'] > 1)
                            $newfilename .= '_'.(strlen($result['file_part_number']-1)==1?'0'.($result['file_part_number']-1):($result['file_part_number']-1));
                        
                    }
                    $phpWord->save(WITHOUTTEMPLATE."$newfilename.docx", "Word2007");
                    
                    $templateFile  = TEMPLATES.$newresult['header'];
                    $generatedFile = WITHOUTTEMPLATE."$newfilename.docx";
                    
                    $targetFile    = $storageDirectory.($includeNoName==1?"":"$newfilename.docx");
                     
                    // copy template to target
                    copy($templateFile, $targetFile);
                    
                    
                    // open target
                    $targetZip = new ZipArchive();
                    $targetZip->open($targetFile);
                    $targetDocument = $targetZip->getFromName('word/document.xml');
                    $targetRelationsDocument = $targetZip->getFromName('word/_rels/document.xml.rels');
                    $targetCorePropsDocument = $targetZip->getFromName('docProps/core.xml');
                    $targetCustomPropsDocument = $targetZip->getFromName('docProps/custom.xml');
                    $targetContentTypesDocument = $targetZip->getFromName('[Content_Types].xml');
                    
                    $targetDom      = new DOMDocument();
                    $targetDom->loadXML($targetDocument);

                    $targetCorePropsDom = new DOMDocument();
                    $targetCorePropsDom->loadXML($targetCorePropsDocument);
                    
                    
                    $targetContentTypesDom = new DOMDocument();
                    $targetContentTypesDom->loadXML($targetContentTypesDocument);
                    
                    $targetXPath = new \DOMXPath($targetDom);
                    $targetXPath->registerNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
                    
                     
                    // open source
                    $sourceZip = new ZipArchive();
                    $sourceZip->open($generatedFile);
                    $sourceDocument = $sourceZip->getFromName('word/document.xml');
                    $sourceRelationsDocument = $sourceZip->getFromName('word/_rels/document.xml.rels');
                    $sourceContentTypesDocument = $sourceZip->getFromName('[Content_Types].xml');

                    $sourceDom      = new DOMDocument();
                    $sourceDom->loadXML($sourceDocument);
                    
                    $sourceRelationsDom = new DOMDocument();
                    $sourceRelationsDom->loadXML($sourceRelationsDocument);

                    $sourceContentTypes = new DOMDocument();
                    $sourceContentTypes->loadXML($sourceContentTypesDocument);

                    $sourceXPath = new \DOMXPath($sourceDom);
                    $sourceXPath->registerNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
                    
                    $sourceRelationsXPath = new \DOMXPath($sourceRelationsDom);
                     
                    $replacementMarkerNode = $targetXPath->query('//w:p[contains(translate(normalize-space(), " ", ""),"$CONTENT$")]')[0];

                    // insert source nodes before the replacement marker
                    $sourceNodes = $sourceXPath->query('//w:document/w:body/*[not(self::w:sectPr)]');
                    
                    $relationsArr = array();
                    $startId = 700;
                    
                    $ifThereAreComments = 0;
                    
                    for ($i = 0; $i < $sourceZip->numFiles; $i++) {
                        if(strpos($sourceZip->getNameIndex($i), 'media') > 0 || strpos($sourceZip->getNameIndex($i), 'comments.xml') > 0){
                            if(strpos($sourceZip->getNameIndex($i), 'comments.xml') > 0)
                                $ifThereAreComments = 1;
                            
                            $imagefile = $sourceZip->getFromName($sourceZip->getNameIndex($i));
                            $temp = fopen(TEMPORARYFILES.substr(bin2hex(random_bytes(5)),0, 5), "w");
                            fwrite($temp, $imagefile);  
                            fseek($temp, 0);
                            
                            $targetZip -> addFile(stream_get_meta_data($temp)['uri'], $sourceZip->getNameIndex($i));
                        }
                            
                    }                   
                    
                    
                    foreach ($sourceNodes as $sourceNode) {
                        $checkifImage = $sourceNode -> getElementsByTagNameNS ("urn:schemas-microsoft-com:vml", 'imagedata');
                        foreach($checkifImage AS $t)
                        {
                            $rid = $t->getAttribute('r:id');
                            $relationsArr[$rid] = array('id'=>'rId'.$startId, 'media'=>'');
                            $t->setAttribute('r:id', $relationsArr[$rid]['id']);
                            $startId++;
                        }
                        
                        $imported = $replacementMarkerNode->ownerDocument->importNode($sourceNode, true);
                        $inserted = $replacementMarkerNode->parentNode->insertBefore($imported, $replacementMarkerNode);
                    }
                    
                    // remove $replacementMarkerNode from the target DOM
                    $replacementMarkerNode->parentNode->removeChild($replacementMarkerNode); 
                      
                    // save target
                    $targetZip->addFromString('word/document.xml', $targetDom->saveXML());
                    
                    $getSourceRelationsTree = $sourceRelationsDom -> getElementsByTagName('Relationship');
                    foreach($getSourceRelationsTree AS $t){
                        $rid = $t->getAttribute('Id');
                        if(isset($relationsArr[$rid])){
                            $relationsArr[$rid]['media'] = $t->getAttribute('Target');
                        }
                    }
                    
                    if($ifThereAreComments){
                        $targetRelationsDom = new DOMDocument();
                        $targetRelationsDom->loadXML($targetRelationsDocument);
                    
                        $parentDom = $targetRelationsDom -> getElementsByTagName('Relationships');
                        $relationsElement = $targetRelationsDom->createElement("Relationship");
                        
                        $domAttribute = $targetRelationsDom->createAttribute('Id');
                        $domAttribute->value = 'rId1000';
                        $relationsElement->appendChild($domAttribute);
                        
                        $domAttribute = $targetRelationsDom->createAttribute('Target');
                        $domAttribute->value = 'comments.xml';
                        $relationsElement->appendChild($domAttribute);
                        $domAttribute = $targetRelationsDom->createAttribute('Type');
                        $domAttribute->value = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
                        $relationsElement->appendChild($domAttribute);
                        
                        $parentDom[0]->appendChild($relationsElement);
                        
                        $targetZip->addFromString('word/_rels/document.xml.rels', $targetRelationsDom->saveXML());
                        
                        
                        $parentDom = $targetContentTypesDom -> getElementsByTagName('Types');
                        $relationsElement = $targetContentTypesDom->createElement("Override");
                        
                        $domAttribute = $targetContentTypesDom->createAttribute('PartName');
                        $domAttribute->value = '/word/comments.xml';
                        $relationsElement->appendChild($domAttribute);
                        
                        $domAttribute = $targetContentTypesDom->createAttribute('ContentType');
                        $domAttribute->value = 'application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml';
                        $relationsElement->appendChild($domAttribute);
                        
                        $parentDom[0]->appendChild($relationsElement);
                        
                        $targetZip->addFromString('[Content_Types].xml', $targetContentTypesDom->saveXML());                        
                        
                    }
                    
                    if(!empty($relationsArr)){
                        $targetRelationsDom = new DOMDocument();
                        $targetRelationsDom->loadXML($targetRelationsDocument);
                    
                        $parentDom = $targetRelationsDom -> getElementsByTagName('Relationships');
                        foreach($relationsArr AS $t){
                            $relationsElement = $targetRelationsDom->createElement("Relationship");
                            
                            $domAttribute = $targetRelationsDom->createAttribute('Id');
                            $domAttribute->value = $t['id'];
                            $relationsElement->appendChild($domAttribute);
                            
                            $domAttribute = $targetRelationsDom->createAttribute('Target');
                            $domAttribute->value = $t['media'];
                            $relationsElement->appendChild($domAttribute);
                            
                            $domAttribute = $targetRelationsDom->createAttribute('Type');
                            $domAttribute->value = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
                            $relationsElement->appendChild($domAttribute);
                            
                            $parentDom[0]->appendChild($relationsElement);
                        }
                        
                        $targetZip->addFromString('word/_rels/document.xml.rels', $targetRelationsDom->saveXML());
                    }
                    
                    $parentDom = $targetCorePropsDom -> getElementsByTagNameNS("http://schemas.openxmlformats.org/package/2006/metadata/core-properties", 'coreProperties');
                    $toRem = $parentDom[0]->getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", 'title')->Item(0);
                    $relationsElement = $targetCorePropsDom->createElement("dc:title", isset($demographics['{{title}}'])?$demographics['{{title}}']['value']:null);
                        
                    $parentDom[0]->appendChild($relationsElement);
                    $toRem->parentNode->removeChild($toRem);
                    
                    $toRem = $parentDom[0]->getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", 'subject')->Item(0);
                    $relationsElement = $targetCorePropsDom->createElement("dc:subject", $dict_id);
                        
                    $parentDom[0]->appendChild($relationsElement);
                    $toRem->parentNode->removeChild($toRem);
                    
                    
                    $targetZip->addFromString('docProps/core.xml', $targetCorePropsDom->saveXML());

                    
                    $targetZip->close();
}

Solution

  • When the target file copied with template file it does not had a numbering.xml file. Due to numbering.xml is not available the bullet points were converted into numbers.

    The target file was written by using DOMXPATH

    $sourceXPath = new \DOMXPath($sourceDom);
    $sourceXPath->registerNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
                        
    $sourceRelationsXPath = new \DOMXPath($sourceRelationsDom);
                         
    $replacementMarkerNode = $targetXPath->query('//w:p[contains(translate(normalize-space(), " ", ""),"$CONTENT$")]')[0];
                         
    $sourceNodes = $sourceXPath->query('//w:document/w:body/*[not(self::w:sectPr)]');
    foreach ($sourceNodes as $sourceNode) {
    
    $imported = $replacementMarkerNode->ownerDocument->importNode($sourceNode, true);
    $inserted = $replacementMarkerNode->parentNode->insertBefore($imported, $replacementMarkerNode);
                        }
    

    Before writing the contents from source to target. Checked numbering is available or not if not then copied numbering from source file and added. It works!

    $phpWord->save(PATH."$newfilename.docx", "Word2007");
    
    $templateFile = TEMPLATES.$newresult['header'];
    $generatedFile = PATH."$newfilename.docx";
    $targetFile = $storageDirectory.($includeNoName==1?"":"$newfilename.docx");
    
    copy($templateFile, $targetFile);
    
    
    // open target
    $targetZip = new \ZipArchive();
    $targetZip->open($targetFile);
    $targetDocument = $targetZip->getFromName('word/document.xml');
    $targetRelationsDocument = $targetZip->getFromName('word/_rels/document.xml.rels');
    $targetCorePropsDocument = $targetZip->getFromName('docProps/core.xml');
    $targetCustomPropsDocument = $targetZip->getFromName('docProps/custom.xml');
    $targetContentTypesDocument = $targetZip->getFromName('[Content_Types].xml');
    $targetDocumentnum = $targetZip->getFromName('word/numbering.xml');
    
    $targetDom = new DOMDocument();
    $targetDom->loadXML($targetDocument);
    
    
    $targetCorePropsDom = new DOMDocument();
    $targetCorePropsDom->loadXML($targetCorePropsDocument);
    
    
    
    $targetContentTypesDom = new DOMDocument();
    $targetContentTypesDom->loadXML($targetContentTypesDocument);
    
    $targetXPath = new \DOMXPath($targetDom);
    $targetXPath->registerNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
    
    
    // open source
    $sourceZip = new \ZipArchive();
    $sourceZip->open($generatedFile);
    $sourceDocument = $sourceZip->getFromName('word/document.xml');
    $sourceRelationsDocument = $sourceZip->getFromName('word/_rels/document.xml.rels');
    
    $sourceDom = new DOMDocument();
    $sourceDom->loadXML($sourceDocument);
    
    $sourceRelationsDom = new DOMDocument();
    $sourceRelationsDom->loadXML($sourceRelationsDocument);
    
    
    $sourceXPath = new \DOMXPath($sourceDom);
    $sourceXPath->registerNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
    
    $sourceRelationsXPath = new \DOMXPath($sourceRelationsDom);
    
    $replacementMarkerNode = $targetXPath->query('//w:p[contains(translate(normalize-space(), " ", ""),"$CONTENT$")]')[0];
    
    // insert source nodes before the replacement marker
    $sourceNodes = $sourceXPath->query('//w:document/w:body/*[not(self::w:sectPr)]');
    
    $relationsArr = array();
    $startId = 700;
    
    $ifThereAreComments = 0;
    for ($i = 0; $i < $sourceZip->numFiles; $i++) {
        print_r(strpos($sourceZip->getNameIndex($i), 'media'));
        if(strpos($sourceZip->getNameIndex($i), 'media') > 0 || strpos($sourceZip->getNameIndex($i), 'comments.xml') > 0
        || strpos($sourceZip->getNameIndex($i), 'numbering.xml') > 0){
        if(strpos($sourceZip->getNameIndex($i), 'comments.xml') > 0)
        $ifThereAreComments = 1;
        if(strpos($sourceZip->getNameIndex($i), 'numbering.xml') > 0)
        $ifThereAreComments = 2;
    
        $imagefile = $sourceZip->getFromName($sourceZip->getNameIndex($i));
        $temp = fopen(TEMPORARYFILES.substr(bin2hex(random_bytes(5)),0, 5), "w");
        fwrite($temp, $imagefile);
        fseek($temp, 0);
    
        $targetZip -> addFile(stream_get_meta_data($temp)['uri'], $sourceZip->getNameIndex($i));
        }
    
        }
    
    
    
        foreach ($sourceNodes as $sourceNode) {
        $checkifImage = $sourceNode -> getElementsByTagNameNS ("urn:schemas-microsoft-com:vml", 'imagedata');
        foreach($checkifImage AS $t)
        {
        $rid = $t->getAttribute('r:id');
        $relationsArr[$rid] = array('id'=>'rId'.$startId, 'media'=>'');
        $t->setAttribute('r:id', $relationsArr[$rid]['id']);
        $startId++;
        }
    
        $imported = $replacementMarkerNode->ownerDocument->importNode($sourceNode, true);
        $inserted = $replacementMarkerNode->parentNode->insertBefore($imported, $replacementMarkerNode);
        }
    
        // remove $replacementMarkerNode from the target DOM
        $replacementMarkerNode->parentNode->removeChild($replacementMarkerNode);
    
        // save target
        $targetZip->addFromString('word/document.xml', $targetDom->saveXML());
    
        $getSourceRelationsTree = $sourceRelationsDom -> getElementsByTagName('Relationship');
        foreach($getSourceRelationsTree AS $t){
        $rid = $t->getAttribute('Id');
        if(isset($relationsArr[$rid])){
        $relationsArr[$rid]['media'] = $t->getAttribute('Target');
        }
        if(isset($relationsArr[$rid])){
        $relationsArr[$rid]['numbering'] = $t->getAttribute('Target');
        }
        }
    
        if($ifThereAreComments){
        $targetRelationsDom = new DOMDocument();
        $targetRelationsDom->loadXML($targetRelationsDocument);
    
        $parentDom = $targetRelationsDom -> getElementsByTagName('Relationships');
        $relationsElement = $targetRelationsDom->createElement("Relationship");
    
        $domAttribute = $targetRelationsDom->createAttribute('Id');
        $domAttribute->value = 'rId1000';
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Target');
        $domAttribute->value = 'comments.xml';
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Type');
        $domAttribute->value = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
        $relationsElement->appendChild($domAttribute);
    
        if(empty($targetDocumentnum)){
    
        $relationsElement = $targetRelationsDom->createElement("Relationship");
    
        $domAttribute = $targetRelationsDom->createAttribute('Id');
        $domAttribute->value = 'rId1001';
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Target');
        $domAttribute->value = 'numbering.xml';
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Type');
        $domAttribute->value = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
        $relationsElement->appendChild($domAttribute);
        }
    
        $parentDom[0]->appendChild($relationsElement);
    
        $targetZip->addFromString('word/_rels/document.xml.rels', $targetRelationsDom->saveXML());
    
    
        $parentDom = $targetContentTypesDom -> getElementsByTagName('Types');
        $relationsElement = $targetContentTypesDom->createElement("Override");
    
        $domAttribute = $targetContentTypesDom->createAttribute('PartName');
        $domAttribute->value = '/word/comments.xml';
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetContentTypesDom->createAttribute('ContentType');
        $domAttribute->value = 'application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml';
        $relationsElement->appendChild($domAttribute);
    
        if(empty($targetDocumentnum)){
    
        $domAttribute = $targetContentTypesDom->createAttribute('PartName');
        $domAttribute->value = '/word/numbering.xml';
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetContentTypesDom->createAttribute('ContentType');
        $domAttribute->value = 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml';
        $relationsElement->appendChild($domAttribute);
        }
    
        $parentDom[0]->appendChild($relationsElement);
    
        $targetZip->addFromString('[Content_Types].xml', $targetContentTypesDom->saveXML());
    
    
        }
    
        if(!empty($relationsArr)){
        $targetRelationsDom = new DOMDocument();
        $targetRelationsDom->loadXML($targetRelationsDocument);
    
        $parentDom = $targetRelationsDom -> getElementsByTagName('Relationships');
        foreach($relationsArr AS $t){
        $relationsElement = $targetRelationsDom->createElement("Relationship");
    
        $domAttribute = $targetRelationsDom->createAttribute('Id');
        $domAttribute->value = $t['id'];
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Target');
        $domAttribute->value = $t['media'];
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Type');
        $domAttribute->value = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
        $relationsElement->appendChild($domAttribute);
    
        $relationsElement = $targetRelationsDom->createElement("Relationship");
    
        $domAttribute = $targetRelationsDom->createAttribute('Id');
        $domAttribute->value = $t['id'];
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Target');
        $domAttribute->value = $t['numbering'];
        $relationsElement->appendChild($domAttribute);
    
        $domAttribute = $targetRelationsDom->createAttribute('Type');
        $domAttribute->value = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
        $relationsElement->appendChild($domAttribute);
    
        $parentDom[0]->appendChild($relationsElement);
        }
    
        $targetZip->addFromString('word/_rels/document.xml.rels', $targetRelationsDom->saveXML());
        }
    
        $parentDom = $targetCorePropsDom -> getElementsByTagNameNS("http://schemas.openxmlformats.org/package/2006/metadata/core-properties", 'coreProperties');
        $toRem = $parentDom[0]->getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", 'title')->Item(0);
        $relationsElement = $targetCorePropsDom->createElement("dc:title", isset($demographics['{{title}}'])?$demographics['{{title}}']['value']:null);
    
        $parentDom[0]->appendChild($relationsElement);
        $toRem->parentNode->removeChild($toRem);
    
        $toRem = $parentDom[0]->getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", 'subject')->Item(0);
        $relationsElement = $targetCorePropsDom->createElement("dc:subject", $dict_id);
    
        $parentDom[0]->appendChild($relationsElement);
        $toRem->parentNode->removeChild($toRem);
    
    
        $targetZip->addFromString('docProps/core.xml', $targetCorePropsDom->saveXML());
        $targetZip->close();