【问题标题】:PHP remove multiple elements with domPHP用dom删除多个元素
【发布时间】:2014-01-08 16:14:36
【问题描述】:

我正在尝试使用 DOM 文档删除 php 中的多个元素,但它无法正常工作。

<iPhone>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>

<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
</iPhone>

我想循环进入我的 xml 文档,然后删除所有元素以获得一个空文件。

这是我在 php 中所做的:

$doc = new DOMDocument;

$doc->load('$myFile'); 
$domNodeList = $doc->getElementsByTagName('enAttentePush'); 
$arraySeen = array(); 
$arrayBug = array(); 

foreach ($domNodeList as $domElement)
{
        //echo('loop / ');
  $tempArray = array(); 

  $aps = $domElement->getElementsByTagName('Message')->item(0)->nodeValue;
  $udid = $domElement->getElementsByTagName('UDID')->item(0)->nodeValue; 
  if (!in_array($udid, $arraySeen))
  {         
      $tempArray[]=$aps; 
      $tempArray[]=$udid; 
      $arrayBug[]=$tempArray;
     $arraySeen[]=$udid; 
   }

   echo("-- removed -- ");
   $domElement->parentNode->removeChild($domElement); 
  }

它只删除一个节点,一般是最后一个。

我该如何循环思考我的节点并在每次看到节点时将其删除?

非常感谢。

【问题讨论】:

  • 如果我记得模糊,删除节点会扰乱节点查询,这意味着您必须重新查询 DOM,直到所有节点都被删除。因此,您应该考虑使用while() { },而不是foreach() { }
  • 好吧,我不知道如何用 dom 做一个 while 循环...

标签: php xml domdocument


【解决方案1】:

getElementsByTagName() 返回“实时”迭代器,当您从列表中删除元素时,列表会发生变化。您可以将迭代器转换为数组以获取列表的副本。

$xml = <<<'XML'
<iPhone>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
</iPhone>
XML;

$dom = new DOMDocument();
$dom->loadXml($xml);

$nodes = iterator_to_array($dom->getElementsByTagName('enAttentePush'));
foreach ($nodes as $node) {
  $node->parentNode->removeChild($node);
}

echo $dom->saveXml();

输出:

<?xml version="1.0"?>
<iPhone>


</iPhone>

更简单的方法是将文档元素从原始文档复制到新文档中 一:

$xml = <<<'XML'
<iPhone>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
<enAttentePush>
  <UDID>dd6fc8032f0bf4c4b3a9c60f523900c9ad463b620a83b6473eda9a12b2c9d47f</UDID>
  <Message>someDataHere</Message>
</enAttentePush>
</iPhone>
XML;

$source = new DOMDocument();
$source->loadXml($xml);

$target = new DOMDocument();
$target->appendChild(
  $target->importNode($source->documentElement, FALSE)
);

echo $target->saveXml();

输出:

<?xml version="1.0"?>
<iPhone/>

要删除特定节点,请使用 Xpath 选择它们。这允许复杂的条件。

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);

$nodes = $xpath->evaluate('/*/enAttentePush');
foreach ($nodes as $node) {
  $node->parentNode->removeChild($node);
}

echo $dom->saveXml();

【讨论】:

  • 非常感谢您,我将使用 stckrboy 解决方案,这对于像我这样的菜鸟来说更简单,但是您的回答对我帮助很大,我会看看 @xPath。非常感谢,非常感谢。
【解决方案2】:

我最近不得不在我自己的网站上执行此操作,发现如果您将元素排列在一个数组中,之后您可以很容易地将它们全部删除。这里有一个小sn-p的使用,希望对你有所帮助:

$doc = new DOMDocument;

$doc->load('$myFile');
$domNodeList = $doc->getElementsByTagName('enAttentePush');

$domArray = array(); //set up an array to catch all our nodes

foreach($domNodeList as $dom) {
    $domArray[] = $dom;
}

// loop through the array and delete each node
foreach($domArray as $node){ 
    $doc->documentElement->removeChild($node);
}

$doc->save('$myFile');

【讨论】:

    【解决方案3】:

    正如评论中已经提到的,使用while 而不是foreach 来迭代DOMNodeList:

    $i = $domNodeList->length;
    while ($i > 0) {
        $i--;
        $domElement = $domNodeList->item($i);
        $domElement->parentNode->removeChild($domElement); 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      相关资源
      最近更新 更多