1

ユーザーが差し込み印刷対応の Word DOCX テンプレート ファイルをアップロードできるようにするソリューションを考え出そうとしています。理想的には、システムが DOCX ファイルを読み取り、XML を抽出し、差し込み印刷フィールドを見つけて、後でマッピングするためにそれらをデータベースに保存します。Zend LiveDocX や PHPDOCX などの SOAP サービスを使用することもできますが、今のところ、DOCX ファイル内のフィールドを識別する方法を理解する必要があります。そのために、私はこの記事から始めました: http://dfmaxwell.wordpress.com/2012/02/24/using-php-to-process-a-word-document-mail-merge/

私は自分のニーズに合わせて少し調整しました (元のコードでも同じエラーが発生しますが、これは問題になる可能性があります)。具体的には、現時点では差し込み印刷を実行するために使用していません。フィールドを識別します。これが私が持っているものです:

    $newFile = '/var/www/mysite.com/public_html/template.docx';

    $zip = new ZipArchive();
    if( $zip->open( $newFile, ZIPARCHIVE::CHECKCONS ) !== TRUE ) { echo 'failed to open template'; exit; }
    $file = 'word/document.xml';
    $data = $zip->getFromName( $file );
    $zip->close();

    $doc = new DOMDocument();
    $doc->loadXML( $data );
    $wts = $doc->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'fldChar');

    $mergefields = array();

    function getMailMerge(&$wts, $index) {
        $loop = true;
        $counter = $index;
        $startfield = false;
        while ($loop) {
            if ($wts->item($counter)->attributes->item(0)->nodeName == 'w:fldCharType') {
                $nodeName = '';
                $nodeValue = '';
                switch ($wts->item($counter)->attributes->item(0)->nodeValue) {
                    case 'begin':
                        if ($startfield) {
                            $counter = getMailMerge($wts, $counter);
                        }
                        $startfield = true;
                        if ($wts->item($counter)->parentNode->nextSibling) {
                            $nodeName = $wts->item($counter)->parentNode->nextSibling->childNodes->item(1)->nodeName;
                            $nodeValue = $wts->item($counter)->parentNode->nextSibling->childNodes->item(1)->nodeValue;
                        }
                        else {
                            // No sibling
                            // check next node
                            $nodeName = $wts->item($counter + 1)->parentNode->previousSibling->childNodes->item(1)->nodeName;
                            $nodeValue = $wts->item($counter + 1)->parentNode->previousSibling->childNodes->item(1)->nodeValue;
                        }
                        if (substr($nodeValue, 0, 11) == ' MERGEFIELD') {
                            $mergefields[] = strtolower(str_replace('"', '', trim(substr($nodeValue, 12))));
                        }
                        $counter++;
                    break;
                case 'separate':
                    $counter++;
                    break;
                case 'end':
                    if ($startfield) {
                        $startfield = false;
                    }
                    $loop = false;
                }
            }
        }
        return $counter;
    }

    for ($x = 0; $x < $wts->length; $x++) {
        if ($wts->item($x)->attributes->item(0)->nodeName == 'w:fldCharType' && $wts->item($x)->attributes->item(0)->nodeValue == 'begin') {
            $newcount = getMailMerge($wts, $x);
            $x = $newcount;
        }
    }

ZipArchive() を使用して DOCX ファイルを開くのに問題はありません。 print_r($doc->saveHTML()); を使用すると、XML データは正常に表示されます。問題は、コードを実行すると致命的なエラーが発生することです。これを指す非オブジェクトのメンバー関数 item() への呼び出し:

$nodeName = $wts->item($counter)->parentNode->nextSibling->childNodes->item(1)->nodeName;

このエラーを理解しようとしているときに Google は私を失望させました。誰かが私を正しい方向に向けることができますか? 前もって感謝します!

4

1 に答える 1

0

解決策を見つけました-それは私が望んでいたほどエレガントではありませんが、ここに行きます.

xml_parser_create_ns を使用して、必要なキー、具体的には「HTTP://SCHEMAS.OPENXMLFORMATS.ORG/WORDPROCESSINGML/2006/MAIN:INSTRTEXT」の DOCX ファイルを検索できます。これは、「MERGEFIELD」としてマークされたすべてのフィールドを識別します。次に、結果を配列にダンプし、それらを使用してデータベースを更新できます。ウィット:

    // Word file to be opened
    $newFile = '/var/www/mysite.com/public_html/template.docx';

    // Extract the document.xml file from the DOCX archive
    $zip = new ZipArchive();
    if( $zip->open( $newFile, ZIPARCHIVE::CHECKCONS ) !== TRUE ) { echo 'failed to open template'; exit; }
    $file = 'word/document.xml';
    $data = $zip->getFromName( $file );
    $zip->close();

    // Create the XML parser and create an array of the results
    $parser = xml_parser_create_ns();
    xml_parse_into_struct($parser, $data, $vals, $index);
    xml_parser_free($parser);

    // Cycle the index array looking for the important key and save those items to another array
    foreach ($index as $key => $indexitem) {
        if ($key == 'HTTP://SCHEMAS.OPENXMLFORMATS.ORG/WORDPROCESSINGML/2006/MAIN:INSTRTEXT') {
            $found = $indexitem;
            break;
        }
    }

    // Cycle *that* array looking for "MERGEFIELD" and grab the field name to yet another array
    // Make sure to check for duplicates since fields may be re-used
    if ($found) {
        $mergefields = array();
        foreach ($found as $field) {
            if (!in_array(strtolower(trim(substr($vals[$field]['value'], 12))), $mergefields)) {
                $mergefields[] = strtolower(trim(substr($vals[$field]['value'], 12)));
            }
        }
    }

    // View the fruits of your labor
    print_r($mergefields);
于 2012-10-24T18:40:34.877 に答える