PHP DOM将xml剪切成碎片,并将每个子节点与父节点分开保存

时间:2014-09-10 08:55:44

标签: php xml dom

我有下一种类型的XML:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test SYSTEM "dtd">
<root>
    <tag1>
        <1>Name</1>
        <2>Num1</2>
        <3>NumOrder</3>
        <4>test</5>
        <6>line</6>
        <7>HTTP  </7>
        <8>1</8>
        <9></9>
    </tag1>
    <tag2>
        <1>Name</1>
        <2>Num1</2>
        <3>NumOrder</3>
        <4>test</5>
        <6>line</6>
        <7>HTTP  </7>
        <8>1</8>
        <9></9>
    </tag2>
    ...
    <tagN>
        <1>Name</1>
        <2>Num1</2>
        <3>NumOrder</3>
        <4>test</5>
        <6>line</6>
        <7>HTTP  </7>
        <8>1</8>
        <9></9>
    </tagN>
</root>

我需要在保存为HTML的数组中分别获取每个子元素的根目录:

array = [rootwithchild1,rootwithchild2 ... N];

 <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE test SYSTEM "dtd">
    <root>
          <tagN>
            <1>Name</1>
            <2>Num1</2>
            <3>NumOrder</3>
            <4>test</5>
            <6>line</6>
            <7>HTTP  </7>
            <8>1</8>
            <9></9>
        </tagN>
   </root>

现在我制作了2个doms,其中一个让所有孩子分开,另一个我已经删除了所有孩子而只留下了根。在这些步骤中,我想将每个子项添加到root,保存为html,删除子项等等,但这并不起作用。

        $bodyNode = $copydoc->getElementsByTagName('root')->item(0);

        foreach ($mini as $value) {
            $bodyNode->appendChild($value);
            $result[] = $copydoc->saveHTML();
            $bodyNode->removeChild($value);
        }
$ bodyNode-&gt; appendChild($ value)上的

错误; Mini 是切割孩子的阵列。 Lib: $ doc = new DOMDocument();

任何人都可以建议如何做到这一点,也许更好地使用xpath或其他东西..? 感谢

2 个答案:

答案 0 :(得分:1)

我只想创建一个只包含root元素和“假”初始子元素的新文档:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test SYSTEM "dtd">
<root>
  <fakechild />
</root>

之后,循环遍历原始文档的子元素 - 并为每个元素执行以下步骤:

  • 使用DOMDocument::importNode

  • 将子节点从原始文档导入新文档
  • 使用DOMNode::replaceChild将根元素的firstChild作为第二个参数替换导入节点的新文档根元素的当前子节点

  • 保存新文件

(在根元素中开始使用<fakechild />在技术上是不必要的,一个简单的空白文本节点也应该这样做 - 但是使用根元素这将不起作用以这种直接的方式,因为firstChild会在第一次循环迭代中给你NULL,所以你不会有一个节点作为第二个参数提供给DOMNode::replaceChild。当然你可以做额外的检查并且使用appendChild而不是replaceChild作为第一项...但为什么复杂的东西超过必要的。)

答案 1 :(得分:0)

DOMNode :: getElemementsByTagName()返回实时结果。因此,如果从DOM中删除节点,它也会从节点列表中删除。

您可以向后迭代列表......

for ($i = $nodes->length - 1; $i >= 0; $i--) {
  $node = $nodes->item($i);
  ...
}

...或将其复制到数组:

foreach (iterator_to_array($nodes) as $node) {
  ...
}

来自DOMXpath :: evaluate()的节点列表不会受到影响。 XPath也允许更具体的节点选择。

$xpath = new DOMXpath($domDocument);
$nodes = $xpath->evaluate('/root/*');
foreach (iterator_to_array($nodes) as $node) {
  ...
}

但我想知道你为什么修改(破坏)原始的XML源?

如果要创建一个新文档作为模板和。永远不要删除节点,只创建新文档并导入它们:

// load the original source
$source= new DOMDocument();
$source->loadXml($xml);
$xpath = new DOMXpath($source);

// create a template dom
$template = new DOMDocument();
$parent = $template;
// add a node and all its ancestors to the template
foreach ($xpath->evaluate('/root/part[1]/ancestor-or-self::*') as $node) {
  $parent = $parent->appendChild($template->importNode($node, FALSE));
}

// for each of the child element nodes
foreach ($xpath->evaluate('/root/part/*') as $node) {
  // create a new target
  $target = new DOMDocument();
  // import the nodes from the template
  $target->appendChild($target->importNode($template->documentElement, TRUE));
  // find the first element node that has no child element nodes
  $targetXpath = new DOMXpath($target);
  $targetNode = $targetXpath->evaluate('//*[count(*) = 0]')->item(0);
  // append the child node from the original xml
  $targetNode->appendChild($target->importNode($node, TRUE));

  echo $target->saveXml(), "\n\n";
}

演示:https://eval.in/191304