PHP 如何插入嵌套元素 Libreoffice 样式

PHP How To Insert Nested Elements Libreoffice Style

Libreoffice 将 Writer 文档内容存储在 XML 格式的文件中。在 PHP 中,我想将具有不同格式的文本插入到文本段落中。不幸的是,Libreoffice 在另一个元素的文本中使用了一个嵌套元素。这是一个简化的例子:

<text:p text:style-name="P1">

   the quick brown
        <text:span text:style-name="T1"> fox jumps over</text:span>      
   the lazy dog

</text:p>

我在 PHP 中没有发现 SimpleXML 或 XML DOM 函数可以让我按照此处的要求在另一个元素的文本中插入一个新元素.我是不是忽略了什么?

SimpleXML 不能很好地处理混合子节点,但在 DOM 中并不难,只是有点冗长。请记住,在 DOM 中任何东西都是一个节点,而不仅仅是元素。因此,您要做的是用三个新节点替换单个文本节点 - 一个文本节点、新元素节点和另一个文本节点。

$xmlns = [
  'text' => 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'
];

$xml = <<<'XML'
<text:p 
   text:style-name="P1" 
   xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">
   the quick brown fox jumps over the lazy dog
</text:p>
XML;

$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);

$searchFor = 'fox jumps over';

// iterate over text nodes containing the search string
$expression = '//text:p//text()[contains(., "'.$searchFor.'")]';
foreach ($xpath->evaluate($expression) as $textNode) {
    // split the text content at the search string and capture any part
    $parts = preg_split(
        '(('.preg_quote($searchFor).'))', 
        $textNode->textContent, 
        -1, 
        PREG_SPLIT_DELIM_CAPTURE
    );
    // here should be at least two parts
    if (count($parts) < 2) {
        continue;
    }
    // fragments allow to treat several nodes like one
    $fragment = $document->createDocumentFragment();
    foreach ($parts as $part) {
        // matched the text
        if ($part === $searchFor) {
            // create the new span
            $fragment->appendChild(
                $span = $document->createElementNS($xmlns['text'], 'text:span')
            );
            $span->setAttributeNS($xmlns['text'], 'text:style-name', 'T1');
            $span->appendChild($document->createTextNode($part));
        } else {
            // add the part as a new text node
            $fragment->appendChild($document->createTextNode($part));
        }   
    }
    // replace the text node with the fragment
    $textNode->parentNode->replaceChild($fragment, $textNode);
}

echo $document->saveXML();