【问题标题】:php/simplexml adding elements before and after textphp/simplexml 在文本前后添加元素
【发布时间】:2017-03-16 19:05:40
【问题描述】:

我正在尝试将元素插入到围绕某些文本的 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; 被转换为&amp;lt&amp;gt,这不好。现在我正在使用$node-&gt;header-&gt;addChild('to', 'Alice')$node[0]-&gt;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>

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

simpleXML 可以吗?

谢谢!

【问题讨论】:

    标签: php xml simplexml children


    【解决方案1】:

    从 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>
    

    【讨论】:

    • 标记为正确答案,因为它以正确的方式进行。比将文件视为文本文件并替换 < 好得多和%gt;与 。我没有把它放在我原来的问题中,但这与我的其他解决方法很接近,即将文件加载为 html 并执行以下操作:

      To Alice from Bob 同时拥有 data-to 和 data-from 可能有点矫枉过正,但是腰带和吊带。谢谢!

    猜你喜欢
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    相关资源
    最近更新 更多