PHPDOM将xml切割成碎片,并将每个子项与父项单独保存

PHPDOM将xml切割成碎片,并将每个子项与父项单独保存,php,xml,dom,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

我有下一种类型的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>
$bodyNode->appendChild($value)上的错误Mini是切割子对象的数组。 Lib:$doc=newDOMDocument()

有没有人能建议如何正确地执行此操作,或者更好地使用xpath或其他方法。。?
谢谢

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源代码

If将创建一个新文档作为模板和。从不删除节点,只创建新文档并导入它们:

// 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";
}

演示:

我只需创建一个新文档,其中只包含
根元素和一个“假”初始子元素:

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

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

  • 使用
    DOMDocument::importNode

  • 使用根元素的
    firstChild
    作为第二个参数,使用导入的节点替换新文档根元素的当前子节点

  • 保存新文档


(从技术上讲,在根元素中首先使用
是不必要的,简单的空白文本节点也应该这样做–但是对于空的根元素,这不会以如此直接的方式工作,因为
第一个子元素
将在第一次循环迭代中为您提供NULL,因此您将没有一个节点可以馈送到DOMNode::replaceChild
作为第二个参数。当然,您可以对其进行额外的检查,并对第一项使用
appendChild
而不是
replaceChild
,但是为什么要使内容变得更加复杂呢。)

您使用的是哪个库?千万别忘了提及这样的事情!抱歉,$doc=new DOMDocument();本机PHP DOM库。我制作了两个不同的DOM:$doc=new-DOMDocument();$doc2=new-DOMDocument();并在其中销毁子节点,以获得一个没有子节点的父节点,这样我可以从第二个列表中插入子节点,保存为html,删除此子节点,插入下一个,等等。谢谢,我的问题是importNode,我想我可以直接使用另一个dom中的节点。最好替换子节点,然后追加并删除它。
// 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";
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test SYSTEM "dtd">
<root>
  <fakechild />
</root>