PHP基于多个节点拆分XML

PHP Split XML based on multiple nodes

老实说,我试图为 php 找到解决方案,但很多线程听起来很相似,但不适用于我或完全不同的语言。

我想根据节点拆分 xml 文件。最好是多个节点,当然一个就够了,可以多次应用。

例如我想用标签 <thingy><othernode>:

分开
<root>
   <stuff />
   <thingy><othernode>one</othernode></thingy>
   <thingy><othernode>two</othernode></thingy>
   <thingy>
      <othernode>three</othernode>
      <othernode>four</othernode>
   </thingy>
   <some other data/>
</root>

理想情况下,我想要 4 个 xml 类型的字符串:

<root>
   <stuff />
   <thingy><othernode>CONTENT</othernode></thingy>
   <some other data/>
</root>

内容为一、二、三和四。 Plottwist:CONTENT 也可以是整个子树。当然它也可以填充各种命名空间和标签前缀(比如<q1:node/>。格式与我无关。


到目前为止,我最好的猜测是 DomDocument、节点克隆和删除除一个节点以外的所有内容?

有趣的问题。

如果我没弄错的话,假设 <othernode> 始终是 <thingy> 的子级,并且每个 <othernode> 的拆分都是在第一个 [=14] 的位置=]在原始文档中。

DOMDocument 在这种情况下显得很有用,因为它允许轻松移动节点 - 包括它的所有子节点。

鉴于节点列表的拆分(来自 getElementsByTagName()):

echo "---\n";
foreach ($split($doc->getElementsByTagName('othernode')) as $doc) {
    echo $doc->saveXML(), "---\n";
}

将所有 <othernode> 元素移动到它自己的 DOMDocumentFragement 中,同时在清空时清理 <thingy> 父元素(除非第一个 anchor 元素),然后暂时将它们中的每一个带回 DOMDocument:

$split = static function (DOMNodeList $nodes): Generator {
    while (($element = $nodes->item(0)) && $element instanceof DOMElement) {
        $doc ??= $element->ownerDocument;
        $basin ??= $doc->createDocumentFragment();
        $anchor ??= $element->parentNode;
        [$parent] = [$element->parentNode, $basin->appendChild($element)];
        $parent->childElementCount || $parent === $anchor || $parent->parentNode->removeChild($parent);
    }

    if (empty($anchor)) {
        return;
    }

    assert(isset($basin, $doc));

    while ($element = $basin->childNodes->item(0)) {
        $element = $anchor->appendChild($element);
        yield $doc;
        $anchor->removeChild($element);
    }
};

这导致以下拆分:

---
<?xml version="1.0"?>
<root>
   <stuff/>
   <thingy><othernode>one</othernode></thingy>
   
   
   <some other="data"/>
</root>
---
<?xml version="1.0"?>
<root>
   <stuff/>
   <thingy><othernode>two</othernode></thingy>
   
   
   <some other="data"/>
</root>
---
<?xml version="1.0"?>
<root>
   <stuff/>
   <thingy><othernode>three</othernode></thingy>
   
   
   <some other="data"/>
</root>
---
<?xml version="1.0"?>
<root>
   <stuff/>
   <thingy><othernode>four</othernode></thingy>
   
   
   <some other="data"/>
</root>
---