PHP Как вставить вложенные элементы в стиле Libreoffice - PullRequest
0 голосов
/ 23 декабря 2018

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, которая позволяла бы мне вставлять новый элемент в текст другого элементакак требуется здесь.Я что-то здесь пропускаю?

1 Ответ

0 голосов
/ 23 декабря 2018

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();
...