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/>
。格式与我无关。
- 我试过 SimpleXml,但它无法轻松写入 dom
- 我尝试了 DomDocument,但我所做的一切似乎都以某种方式破坏了 links/relation 个 parent/child 节点。
- 我试过 XmlReader/Writer,但维护和组合起来非常困难(至少对我而言)。
到目前为止,我最好的猜测是 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>
---
老实说,我试图为 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/>
。格式与我无关。
- 我试过 SimpleXml,但它无法轻松写入 dom
- 我尝试了 DomDocument,但我所做的一切似乎都以某种方式破坏了 links/relation 个 parent/child 节点。
- 我试过 XmlReader/Writer,但维护和组合起来非常困难(至少对我而言)。
到目前为止,我最好的猜测是 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>
---