php / simplexml在文本前后添加元素

时间:2017-03-16 19:05:41

标签: php xml simplexml children

我正在尝试将元素插入到某些文本周围的xml文档中。问题的一部分可能是这不是格式良好的xml,并且它需要更容易阅读作为纯文本的人。所以我拥有的是这样的:

<record>
  <letter>
    <header>To Alice from Bob</header>
    <body>Hi, how is it going?</body>
  </letter>
</record>

我需要最终得到这个:

<record>
  <letter>
    <header>To <to>Alice</to> from <from>Bob</from></header>
    <body>Hi, how is it going?</body>
  </letter>
</record>

类似的东西应该是有效的html:

<p>To <span>Alice</span> from <span>Bob</span></p>

我可以将标头的值设置为字符串,但<>转换为&lt&gt,这是不行的。现在我正在使用$node->header->addChild('to', 'Alice')$node[0]->header = 'plain text'

如果我这样做

$node->header->addChild('to', 'Alice'); 
$node->header = 'plain text';
$node->header->addChild('from', 'Bob'); 

然后我得到

<header>plain text <from>Bob</from></header>

'to'被消灭了。

快速而肮脏的方法就是让它成为

<header>plain text <to>Alice</to><from>Bob</from></header>

然后再次打开文件并移动元素。或者搜索并替换&amp; lt和&amp; gt。这似乎是错误的方式。

这可以用simpleXML吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

从DOM(而SimpleXML是一个抽象)的角度来看,你不要在文本周围插入元素。使用混合的文本节点和元素节点替换文本节点。 SimpleXML在混合子节点上存在一些问题,因此您可能希望直接使用DOM。这是一个注释的例子:

$xml = <<<'XML'
<record>
  <letter>
    <header>To Alice from Bob</header>
    <body>Hi, how is it going?</body>
  </letter>
</record>
XML;

// the words and the tags you would like to create
$words = ['Alice' => 'to', 'Bob' => 'from'];
// a split pattern, you could built this from the array
$pattern = '((Alice|Bob))';

// bootstrap the DOM
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);

// iterate any text node with content
foreach ($xpath->evaluate('//text()[normalize-space() != ""]') as $text) {
  // use the pattern to split the text into an list
  $parts = preg_split($pattern, $text->textContent, -1, PREG_SPLIT_DELIM_CAPTURE);
  // if it was split actually
  if (count($parts) > 1) {
    /// iterate the text parts
    foreach ($parts as $part) {
      // if it is a word from the list
      if (isset($words[$part])) {
        // add the new element node
        $wrap = $text->parentNode->insertBefore(
          $document->createElement($words[$part]),
          $text
        );
        // and add the text as a child node to it
        $wrap->appendChild($document->createTextNode($part));
      } else {
        // otherwise add the text as a new text node
        $text->parentNode->insertBefore(
          $document->createTextNode($part),
          $text
        );
      }
    }
    // remove the original text node
    $text->parentNode->removeChild($text);
  }
}

echo $document->saveXml();

输出:

<?xml version="1.0"?>
<record>
  <letter>
    <header>To <to>Alice</to> from <from>Bob</from></header>
    <body>Hi, how is it going?</body>
  </letter>
</record>