如何在div父节点中追加子节点?

时间:2015-09-29 08:35:36

标签: php xml dom xpath

我需要将子节点附加到其父节点,但父节点应为div

我需要检查,如果父节点不是div,那么检查父节点,直到我得到div节点。怎么做?

XML文件

    <div class="parent">
      <div class="boxed-text">box text1</div>
      <li>
        <div class="boxed-text">box text2</div>
        <p>para</p>
      </li>
      <div class="boxed-text">box text3</div>
      <p>para</p>
    </div>

预期输出(应附加到div父节点)

    <div class="parent">
      <li>
        <p>para</p>
      </li>     
      <p>para</p>
      <div class="boxed-text">box text1</div>
      <div class="boxed-text">box text2</div>
      <div class="boxed-text">box text3</div>
    </div>

但是我得到了如下输出:(即盒装文本2的父节点是li标签,所以它被附加到那里而不是div父节点。如何只获得div父节点来附加子节点节点?)

    <div class="parent">
      <li>
        <p>para</p>
        <div class="boxed-text">box text2</div>
      </li>     
      <p>para</p>
      <div class="boxed-text">box text1</div>
      <div class="boxed-text">box text3</div>
    </div>

我的代码:

$dom = new DOMDocument;
$dom->load("new_test.xml", LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xp = new DOMXPath($dom);
$xp->registerNamespace("php", "http://php.net/xpath");
$div = $xp->query("//div[@class='boxed-text']");
foreach($div as $divv) {
    $divv->parentNode->appendChild($divv);
    }
$r = $dom->saveXML();

2 个答案:

答案 0 :(得分:1)

您将节点附加到其父节点,但这只会将它们移动到父节点内的最后位置 - 它不会更改父节点。

Xpath有一个轴的概念。默认轴为child - 当前上下文的子项。但是这里有几个其他的,包括ancestor,它代表了返回文档根目录的路径。

$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->load("new_test.xml", LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xp = new DOMXPath($dom);
$xp->registerNamespace("php", "http://php.net/xpath");

$divs = $xp->evaluate("//div[@class='boxed-text']");
foreach($divs as $div) {
  $ancestor = $xp->evaluate('ancestor::div[1]', $div)->item(0);
  if ($ancestor) {
    $ancestor->appendChild($div);
  }
}

echo $dom->saveXML();

输出:

<?xml version="1.0"?>
<div class="parent">
  <li>
    <p>para</p>
  </li>
  <p>para</p>
  <div class="boxed-text">box text1</div>
  <div class="boxed-text">box text2</div>
  <div class="boxed-text">box text3</div>
</div>

另一种方法是遍历父div元素并为每个元素获取盒装文本后代:

$parents = $xp->evaluate("//div[.//div[@class='boxed-text']]");
foreach ($parents as $parent) {
  foreach ($xp->evaluate(".//div[@class='boxed-text']", $parent) as $text) {
    $parent->appendChild($text);
  }
}

答案 1 :(得分:0)

下面的代码未经过测试,但我会使用XPath显式获取父节点,而不是使用当前的parentNode方法,并在第一个循环中从dom中删除div元素,然后在最后添加它们

$tmp=array();
$dom = new DOMDocument;
$dom->load( "new_test.xml", LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );

$xp = new DOMXPath( $dom );
$xp->registerNamespace("php", "http://php.net/xpath");

/* Find the parent based on it's class */
$parent=$xp->query("//div[class='parent']")->item(0);

/* Find the nodes of interest and remove - store in temp array */
$col = $xp->query("//div[@class='boxed-text']");
foreach( $col as $node ) $tmp[]=$parent->removeChild( $node );

/* Add the nodes back at the end */
foreach( $tmp as $node ) $parent->appendChild( $node );

$r = $dom->saveXML();